10

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) 进行扩展具有以下优点:

  1. 正如他们上面所说,我们可以使用函数文字进行组合。
  2. 我们不会生成 .class 文件,编译器要做的事情会更少(理论上)。

但是,它有以下缺点:

  1. 要在同一个命名空间(包)中可用,您需要在包对象中定义类型,该对象可能位于使用站点的另一个文件中。
  2. 您不能在 Eclipse 中的别名上跳转 'Open Type' ctrl-shift-T,但您可以在 Eclipse 中打开声明 (F3)。这可能会在未来得到解决。
  3. 您不能使用其他语言(例如 Java)的类型别名。
  4. 如果类型别名是参数化的,那么擦除会阻止模式匹配以与特征相同的方式工作。

第四点对我来说是最严重的:

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

编译器对第一个模式匹配发出警告,这显然不能按预期工作。

所以,最后,这个问题。使用类型别名而不是扩展特征/类还有其他优点或缺点吗?

4

2 回答 2

8

我认为它们的关键实际上是类型别名和特征确实不同。差异列表不胜枚举:

  1. 速记语法适用于类型别名(例如x => x+7将作为 a 工作type I2I = Int => Int)而不是特征。
  2. 特征可以携带额外的数据,类型别名不能。
  3. 隐式适用于类型别名,但不适用于特征。
  4. 特征以类型别名不提供的方式提供类型安全/匹配。
  5. 类型别名对在子类中被覆盖有严格的规定;取而代之的是同名特征阴影(任何事情都会发生)。

其中。

这是因为你在这两种情况下做的事情截然不同。类型别名只是一种表达方式,“好吧,当我输入 Foo 时,我实际上是指 Bar。它们是一样的。明白吗?很酷。” 完成此操作后,您可以随时随地替换该名称FooBar唯一的限制是,一旦你决定了类型是什么,你就不能改变主意

另一方面,Traits 创建了一个全新的界面,它可以扩展 trait 扩展的内容,也可以不扩展。如果不是,它仍然是一个标记,表明这是它自己的实体类型,可以进行模式匹配,使用“isInstanceOf”进行测试,等等。

所以,既然我们已经确定它们确实不同,问题是如何使用它们。答案很简单:如果你喜欢现有的类,只是不喜欢它的名字,那就使用类型别名。如果您想创建自己的不同于其他事物的新实体,请使用特征(或子类)。前者主要是为了方便,而后者是为了增加类型安全性或功能。我认为没有任何规则说使用一个而不是另一个真正抓住了这一点——了解两者的特性,并在你想要的特性时使用它们。

(然后是存在类型,它提供与泛型类似的功能......但让我们把它留给另一个问题。)

于 2012-10-17T21:36:12.123 回答
2

They are different in that a type alias defines type equality relationship (ie. T1 <: T2 && T1 >: T2) while trait extension defines a strict sub-type relationship (ie. T1 <: T2 && !(T1 >: T2)). Use them wisely.

于 2012-10-18T11:19:41.793 回答