月度归档:2013年09月

scala类型系统:9) this别名&自身类型

看scala的源码的话很发现很多源码开头都有一句:self => 这句相当于给this起了一个别名为self

class A { 
    self =>  //this别名
    val x=2 
    def foo = self.x + this.x 
}

self不是关键字,可以用除了this外的任何名字命名(除关键字)。就上面的代码,在A内部,可以用this指代当前对象,也可以用self指代,两者是等价的。

它的一个场景是用在有内部类的情况下:

class Outer { outer => 
    val v1 = "here"
    class Inner {
        println(outer.v1) // 用outer表示外部类,相当于Outer.this
    }
}

对于this别名 self =>这种写法形式,是自身类型(self type)的一种特殊方式。

self在不声明类型的情况下,只是this的别名,所以不允许用this做this的别名

scala> class C { this => } //error 不能用this做别名

但当声明了类型的时候,就不是别名的用途了,这个时候表示自身类型,比如:

scala> class C { this:X => }

this:X => 要求C在实例化时或定义C的子类时,必须混入指定的X类型,这个X类型也可以指定为当前类型

scala> class C { this:C => } // 不会报错

自身类型的存在相当于让当前类变得“抽象”了,它假设当前对象(this)也符合指定的类型,因为自身类型 this:X =>的存在,当前类构造实例时需要同时满足X类型

scala> new C // 不满足
<console>:10: error: class C cannot be instantiated because it does not conform to its self-type C with X

// ok, 相当于构造一个复合类型(C with X)的实例
scala> val c = new C with X

在定义C的子类时,因为自身类型的约束,也必须满足X类型,即子类必须也混入X

scala> class D extends C with X

注意上面两种情况下X都为特质(trait)。

如果自身类型是定义在特质中(大多情况下):

scala> trait T { this:X => } 

那么当某个class或object 要继承或混入 T 时,必须也要满足 X 类型,如果该类/单例不是X的子类的话就要同时混入X才可以

scala> object A extends T with X

最后,自身类型也可以声明为复合类型

this: X with Y with Z => 

或声明为结构类型

this: { def close:Unit} => 

另外,自身类型中,可以用this也可以用其他名字,如self

scala类型系统:8) type关键字

scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型。

type相当于声明一个类型别名:

scala> type S = String
defined type alias S

上面把String类型用S代替,通常type用于声明某种复杂类型,或用于定义一个抽象类型。

场景1 用于声明一些复杂类型,比如下面声明一个结构类型

scala> type T = Serializable {
 |          type X
 |          def foo():Unit
 |     }
defined type alias T

这个结构类型内部也允许通过type来定义类型,这里对X没有赋值表示X是一个抽象类型,需要子类型在实现时提供X具体的类型。下面是一个T类型的具体实例:

scala> object A extends Serializable{ type X=String; def foo(){} }

scala> typeOf[A.type] <:< typeOf[T]
res19: Boolean = true

场景2 用于抽象类型

scala> trait A { type T ; def foo(i:T) = print(i) }

scala> class B extends A { type T = Int }

scala> val b = new B

scala> b.foo(200)
200

scala> class C extends A { type T = String }

scala> val c = new C

scala> c.foo("hello")
hello

scala类型系统:6) 复合类型与with关键字

上次上海scala聚会回来,把《快学scala》借给王福强看了几天,他写过一篇”scala for the impatient琐碎记录”,其中 多Trait与继承的解读

class A extends B with C with D with E 

应做类似如下形式解读:

class A extends (B with C with D with E)

这正是《scala for the impatient》这本书上的内容,我下面的理解也基本源于这本书。

T1 with T2 with T3 …

这种形式的类型称为复合类型(compound type)或者也叫交集类型(intersection type)。

跟结构类型类似,可以在一个方法里声明类型参数时使用复合类型:

scala> trait X1; trait X2;

scala> def test(x: X1 with X2) = {println("ok")}
test: (x: X1 with X2)Unit

scala> test(new X1 with X2)
ok

scala> object A extends X1 with X2

scala> test(A)
ok

也可以通过 type 声明:

scala> type X = X1 with X2
defined type alias X

scala> def test(x:X) = println("OK")
test: (x: X)Unit

scala> class A extends X1 with X2

scala> val a = new A

scala> test(a)
OK

在上一篇介绍结构类型时也提到过复合类型中也可包含结构类型:

scala> type X = X1 with X2 { def close():Unit }
defined type alias X

scala类型系统:5) 结构类型

结构类型(structural type)为静态语言增加了部分动态特性,使得参数类型不再拘泥于某个已命名的类型,只要参数中包含结构中声明的方法或值即可。举例来说,java里对所有定义了close方法的抽象了一个Closable接口,然后再用Closable类型约束参数,而scala里可以不要求参数必须继承自Closable接口只需要包含close方法;如下:

scala> def free( res: {def close():Unit} ) { 
            res.close 
        }

scala> free(new { def close()=println("closed") })
closed

也可以通过type在定义类型时,将其声明为结构类型

scala> type X = { def close():Unit }
defined type alias X

scala> def free(res:X) = res.close

scala> free(new { def close()=println("closed") })
closed

上面传入参数时,都是传入一个实现close方法的匿名类,如果某个类/单例中实现了close方法,也可以直接传入

scala> object A { def close() {println("A closed")} }

scala> free(A)
A closed

scala> class R { def close()=print("ok") }

scala> val r = new R

scala> free(r)
ok

结构类型还可以用在稍微复杂一点的“复合类型”中,比如:

scala> trait X1; trait X2;

scala> def test(x: X1 with X2 { def close():Unit } ) = x.close

上面声明test方法参数的类型为:

X1 with X2 { def close():Unit }

表示参数需要符合特质X1和X2同时也要有定义close方法。对于“复合类型”下一篇再介绍。