这次聚会中分享的《scala类型系统》中,对于结构类型,有一页中有错误,纠正一下。
这页ppt中,上面一行代码中的 {val name:String}
是结构类型,但下面一行中{val name="wang"}
在这种情况下并不是结构类型,而是Early definition
我们看一下scala规范里对Early definition的定义:
{ val p1:T1 =e1
...
val pn: Tn = en
} with sc with mt1 with mtn {stats}
在这种情况下,大括号这部分并不是结构类型,只是相当于把部分成员在父类初始化之前提前初始化而已。大括号后边的sc
是指父类构造器。
然后再说说对结构类型的理解,还是那页ppt里的例子:
trait T extends { val name:String }
等价于
trait T extends AnyRef { val name:String }
在scala语言规范描述复合类型(compound type)时,也说到:
A compound type may also consist of just a refinement {R } with no preceding component types. Such a type is equivalent to AnyRef{R }.
复合类型可以只是 {refinement}
部分,前边可以不要其他 component type,它等价于 AnyRef{refinement}
,这么看结构类型算是复合类型的一个特例。
在scala语言规范里,也没有专门定义“结构类型”的章节,只是在2.6版本修订时,提到可以声明结构类型:
Changes in Version 2.6 (27-July-2007) It is now possible to declare structural types using type refinements (§3.2.7).
结构类型中的”structural“这个词也是来自规范对compound type描述时:{refinement}
部分如果包含声明或类型定义(没有覆盖其他component type),则说这部分的声明或定义是“结构化的”。
A compound type
T1 with . . . with Tn {R }
represents objects with members as given in the component typesT1, ..., Tn
and the refinement{R }
. A refinement{R }
contains declarations and type definitions. If a declaration or definition overrides a declaration or definition in one of the component types T1, …, Tn, the usual rules for overriding apply; otherwise the declaration or definition is said to be “structural”.
另外对于结构类型中的类型参数,还有一个约束,看下面的例子:
scala> def f( p: {def id[T](i:T) } ) {
//donothing
}
f: (p: AnyRef{def id[T](i: T): Unit})Unit
上面f函数的参数p 是一个结构类型,它内部声明了一个方法id
,该方法带有类型参数。如果类型参数是在结构类型自己的上下文定义的(上面的情况),编译和运行都没有问题:
scala> f( new { def id[String](i:String)=print(i) })
//运行ok
但如果结构类型中声明的方法需要外部的类型参数,比如:
scala> def f[T]( p: {def id(i:T) } ) {
//donothing
}
<console>:7: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
编译时会有错误,提示不能使用定义在外部的抽象类型。但是对于返回值使用外部的类型参数却没有问题:
scala> def f[T]( p: {def id():T } ) {
//donothing
}
//编译ok f: [T](p: AnyRef{def id(): T})Unit
这个原因是scala在jvm上实现,受限于jvm运行时采取的类型擦拭,结构类型背后通过反射来执行的,丢失了类型信息所致。细节解释可以参考:这里
今天就碰到了这个问题
class AAA[ K, T <: { def +=(t:T) : T } ] {
// some code…
}
我想表达的是 AAA这个类的两个泛型参数[K, T] 中, 要求 T类型有 +=(t:T) : T 的方法. 结果就报了这个错. error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
看来这样是不允许的了 对吧. 类型擦除的问题.
trait A extends {val name:String = “wang”}
这里面是结构类型还是early initializers