2019独角兽企业重金招聘Python工程师标准>>>
###翻译:http://dotty.epfl.ch/docs/reference/intersection-types.html #交叉类型
trait Resettable {def reset(): this.type
}
trait Growable[T] {def add(x: T): this.type
}
def f(x: Resettable & Growable[String]) = {x.reset()x.add("first")
}
这里x要求必须是Resettable
类型和Growable[T]
类型,交叉类型A & B
替代了scala2中的复合类型A with B
(目前,这种复合类型仍然可以使用,但是未来会被废除)
与 with
复合类型不同,&
交叉类型是可互换的,比如:A & B
和B & A
是相同的类型。 一个交叉类型A & B
的所有成员,是类型A
的所有成员和类型B
的所有成员之和。
例如Resettable & Growable[String]
类型拥有reset
和add
两个分别来自两个类型的成员方法。
如果一个成员既出现在A
类型中,又出现在B
类型中,那么这个成员的类型在类型A & B
中表现为A
类型和B
类型交叉。比如下面的例子:
trait A {def children: List[A]def say:Int = 1
}
trait B {def children: List[B]def say:String = "2"
}
class C extends A with B {def children: List[A & B] = List(new C)override def say:Int & String = super.say + 3}
val x: A & B = new C
val xs: List[A] & List[B] = x.children
val ys: List[A & B] = x.children
这个成员children
在 A & B
的类型,是 children
在A
中的类型List[A]
和children
在B
中类型List[B]
的交叉类型List[A] & List[B]
。这个能进一步简化为List[A & B]
,因为List
是协变的。
联合类型
翻译:http://dotty.epfl.ch/docs/reference/union-types.html
操作符|
创建一个联合类型
case class UserName(name: String) {def lookup(admin: Admin): UserData
}
case class Password(hash: Hash) {def lookup(admin: Admin): UserData
}def help(id: UserName | PassWord) = {val user = id match {case UserName(name) => lookupName(name)case Password(hash) => lookupPassword(hash)}// ...
}
联合类型是双重交叉类型。联合类型A|B
的值是所有A
的值和所有B
的值之和。 |
联合类型是可互换的,比如:A | B
和B | A
是相同的类型。
只有当一个表达式明确给出类型的时候,编译器才会给这个表达式赋值一个联合类型,例如:
scala> val password = Password(123)
val password: Password = Password(123)
scala> val name = UserName("Eve")
val name: UserName = UserName(Eve)
scala> if (true) name else password
val res2: Object & Product = UserName(Eve)
scala> val either: Password | UserName = if (true) name else password
val either: Password | UserName = UserName(Eve)
scala>help(either)
res2
的类型是Object & Product
,它是 UserName
和 Product
的一个超类,但不是类型的最小超类Password | UserName
。如果想获得最小超类,必须明确给出类型定义,就像这里的val either: Password | UserName
的类型。要调用联合类型的成员,使用类型匹配match
,比如这里的help
方法
#文本单例类型 看以下例子:
object Literals{val fortyTwo: 42 = 42val `2`: 2 = 2val fortyFour: 44 = fortyTwo + `2`val text: "text" = "text"def id[T](a: T) = aval two: 2 = id(`2`)final val T = 1
val x: T.type = 2 // error , 2 should be 1
}
这里 val x: T.type = 2
会报错,因为T.type
文本类型只能赋值为原本定义的值,这里是1
。这里的final val
定义个值不可变的单例文本类型,使用T.type
来引用,且只能赋值为原值。