scala类型系统:17) 结构类型的细节问题

这次聚会中分享的《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 types T1, ..., 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运行时采取的类型擦拭,结构类型背后通过反射来执行的,丢失了类型信息所致。细节解释可以参考:这里

发表评论

电子邮件地址不会被公开。 必填项已用*标注