在Twitter Effective Scala - Type Aliases中,他们说:
当别名发生时,不要使用子类.
Run Code Online (Sandbox Code Playgroud)trait SocketFactory extends (SocketAddress => Socket)SocketFactory是一个生成Socket的函数.使用类型别名
Run Code Online (Sandbox Code Playgroud)type SocketFactory = SocketAddress => Socket更好.现在,我们可以针对类型的SocketFactory的值提供了函数文本,还可以使用函数组合:VAL addrToInet:为SocketAddress =>长VAL inetToSocket:长=>插座
Run Code Online (Sandbox Code Playgroud)val factory: SocketFactory = addrToInet andThen inetToSocket请注意,类型别名不是新类型 - 它们等同于语法上用别名替换其类型.
我们谈论的那种事情是:
trait Base
trait T1 extends Base // subclassing
type T2 = Base // type alias
Run Code Online (Sandbox Code Playgroud)
显然,当类/特征具有正文或存储信息时,您不能使用类型别名作为替换.
因此,使用类型别名(T2)而不是使用特征或类(T1)进行扩展具有以下优点:
但是,它有以下缺点:
第四点对我来说是最严重的:
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" }))
Run Code Online (Sandbox Code Playgroud)
这会产生:
T3
T2
Run Code Online (Sandbox Code Playgroud)
编译器会发出有关第一个模式匹配的警告,这显然不能按预期工作.
所以,最后,问题.使用类型别名而不是扩展特征/类是否有任何其他优点或缺点?
我认为它们的关键实际上是类型别名和特征真的不同.差异列表一直在继续:
x => x+7将作为a type I2I = Int => Int)而不是特征.等等.
这是因为在这两种情况下你做了截然不同的事情.类型别名只是一种说法,"好吧,当我输入Foo时,我实际上是指Bar.他们是相同的.知道了吗?很酷." 完成这一步之后,您可以替换名称Foo为Bar无论何时何地,你喜欢它的感觉.唯一的限制是,一旦你决定了什么类型,你就无法改变主意.
另一方面,特征创建了一个全新的界面,可以根据特征的扩展范围扩展,也可以不扩展.如果没有,它仍然是一个标记,这是它自己的实体类型,可以进行模式匹配,使用'isInstanceOf'进行测试,依此类推.
所以,既然我们已经确定它们真的不同,那么问题就是如何使用它们.答案很简单:如果您喜欢现有的类,除了您不喜欢名称,请使用类型别名.如果要创建与其他事物不同的新实体,请使用特征(或子类).前者主要是为了方便,后者是为了增加类型安全性或能力.我不认为任何规则说使用一个而不是另一个真正抓住了这一点 - 理解两者的特征,并在那些是你想要的功能时使用它们.
(然后是存在类型,它们提供类似于泛型的能力......但是让我们留下另一个问题.)
| 归档时间: |
|
| 查看次数: |
2541 次 |
| 最近记录: |