【发布时间】:2012-10-17 20:47:26
【问题描述】:
在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
编译器对第一个模式匹配发出警告,这显然不能按预期工作。
所以,最后,这个问题。使用类型别名而不是扩展特征/类还有其他优点或缺点吗?
【问题讨论】:
-
模式匹配对我来说很有意义,尽管我确实不得不考虑一分钟。
T3作为类型别名意味着您可以在任何地方用T1[Any]替换T3。所以第一场比赛真的是c match { cast t: T1[Any] => "T3"; ... }。c是C2,它是T1[Any]的子类型(通过T2)。所以 not 匹配模式实际上会更令人惊讶。 -
标签: scala