交集类型 - 更多细节
语法
从语法上讲,类型 S & T 是一个中缀类型,其中中缀运算符是 &。运算符 & 是一个普通的标识符,具有通常的优先级,并受通常的解析规则约束。除非被其他定义遮蔽,否则它解析为类型 scala.&,它充当交集类型的内部表示的类型别名。
Type ::= ...| InfixType
InfixType ::= RefinedType {id [nl] RefinedType}
子类型规则
T <: A T <: B
----------------
T <: A & B
A <: T
----------------
A & B <: T
B <: T
----------------
A & B <: T
从上面的规则可以看出,& 是可交换的:对于任何类型 A 和 B,A & B <: B & A。
B <: B A <: A
---------- -----------
A & B <: B A & B <: A
---------------------------
A & B <: B & A
换句话说,A & B 与 B & A 的类型相同,因为这两种类型具有相同的取值,并且彼此是子类型。
如果 C 是一个协变或逆变类型构造器,那么 C[A] & C[B] 可以使用以下规则简化
- 如果
C是协变的,C[A] & C[B] ~> C[A & B] - 如果
C是逆变的,C[A] & C[B] ~> C[A | B]
当 C 是协变时,可以推导出 C[A & B] <: C[A] & C[B]
A <: A B <: B
---------- ---------
A & B <: A A & B <: B
--------------- -----------------
C[A & B] <: C[A] C[A & B] <: C[B]
------------------------------------------
C[A & B] <: C[A] & C[B]
当 C 是逆变时,可以推导出 C[A | B] <: C[A] & C[B]
A <: A B <: B
---------- ---------
A <: A | B B <: A | B
------------------- ----------------
C[A | B] <: C[A] C[A | B] <: C[B]
--------------------------------------------------
C[A | B] <: C[A] & C[B]
擦除
S & T 的擦除类型是 S 和 T 的擦除类型的擦除glb(最大下界)。擦除交集类型的规则在下面的伪代码中给出
|S & T| = glb(|S|, |T|)
glb(JArray(A), JArray(B)) = JArray(glb(A, B))
glb(JArray(T), _) = JArray(T)
glb(_, JArray(T)) = JArray(T)
glb(A, B) = A if A extends B
glb(A, B) = B if B extends A
glb(A, _) = A if A is not a trait
glb(_, B) = B if B is not a trait
glb(A, _) = A // use first
在上面,|T| 表示 T 的擦除类型,JArray 指的是 Java 数组的类型。
另请参阅:TypeErasure#erasedGlb.
与复合类型(with)的关系
交集类型 A & B 在 Scala 2 中替换了复合类型 A with B。目前,语法 A with B 仍然允许使用,并解释为 A & B,但它作为类型(与在 new 或 extends 子句中不同)的使用将在将来被弃用并删除。
本文档