在Twitter Effective Scala - Type Aliases中,他们说:
当别名可以使用时,不要使用子类化。
trait SocketFactory extends (SocketAddress => Socket)
SocketFactory 是一个产生 Socket 的函数。使用类型别名
type SocketFactory = SocketAddress => Socket
更好。我们现在可以为 SocketFactory 类型的值提供函数字面量,也可以使用函数组合: val addrToInet: SocketAddress => Long val inetToSocket: Long => Socket
val factory: SocketFactory = addrToInet andThen inetToSocket
请注意,类型别名不是新类型——它们等同于在语法上用别名替换其类型。
我们正在谈论的事情是:
trait Base
trait T1 extends Base // subclassing
type T2 = Base // type alias
显然,当类/特征具有主体或存储信息时,您不能使用类型别名作为替代。
因此,使用类型别名 (T2) 而不是使用特征或类 (T1) 进行扩展具有以下优点:
- 正如他们上面所说,我们可以使用函数文字进行组合。
- 我们不会生成 .class 文件,编译器要做的事情会更少(理论上)。
但是,它有以下缺点:
- 要在同一个命名空间(包)中可用,您需要在包对象中定义类型,该对象可能位于使用站点的另一个文件中。
- 您不能在 Eclipse 中的别名上跳转 'Open Type' ctrl-shift-T,但您可以在 Eclipse 中打开声明 (F3)。这可能会在未来得到解决。
- 您不能使用其他语言(例如 Java)的类型别名。
- 如果类型别名是参数化的,那么擦除会阻止模式匹配以与特征相同的方式工作。
第四点对我来说是最严重的:
trait T1[T]
trait T2 extends T1[Any]
type T3 = T1[Any]
class C2 extends T2
val c = new C2
println("" + (c match { case t: T3 => "T3"; case _ => "any" }))
println("" + (c match { case t: T2 => "T2"; case _ => "any" }))
这会产生:
T3
T2
编译器对第一个模式匹配发出警告,这显然不能按预期工作。
所以,最后,这个问题。使用类型别名而不是扩展特征/类还有其他优点或缺点吗?