在 GitHub 上编辑此页面

联合类型

联合类型 A | B 包括两种类型的全部值。

trait ID
case class UserName(name: String) extends ID
case class Password(hash: Hash) extends ID

def help(id: UserName | Password) =
  val user = id match
    case UserName(name) => lookupName(name)
    case Password(hash) => lookupPassword(hash)
  ...

联合类型是交集类型的对偶。|可交换的A | BB | A 是同一种类型。

只有在明确给出联合类型或所有备选方案的公共超类型是透明的时,编译器才会将联合类型分配给表达式。

这可以在以下 REPL 记录中看到

scala> val password = Password(123)
val password: Password = Password(123)

scala> val name = UserName("Eve")
val name: UserName = UserName(Eve)

scala> if true then name else password
val res1: ID = UserName(Eve)

scala> val either: Password | UserName = if true then name else password
val either: UserName | Password = UserName(Eve)

res1 的类型是 ID,它是 UserNamePassword 的超类型,但不是最小超类型 UserName | Password。如果我们想要最小超类型,则必须显式给出它,就像 either 的类型所做的那样。

如果公共超特征 ID 被声明为 transparent,则推理行为会发生变化

transparent trait ID

在这种情况下,联合类型不会被扩展。

scala> if true then name else password
val res2: UserName | Password = UserName(Eve)

如果 UserNamePassword 在没有显式父类的情况下被声明,那么也会推断出更精确的联合类型,因为在这种情况下,它们隐含的超类是 Object,而 Object 是被认为是透明的类之一。有关此类类的列表,请参见透明特征和类

case class UserName(name: String)
case class Password(hash: Hash)

scala> if true then UserName("Eve") else Password(123)
val res3: UserName | Password = UserName(Eve)

更多详情