好风格:键入别名vs子类化空类/特征

时间:2012-10-17 20:47:26

标签: scala

Twitter Effective Scala - Type Aliases中,他们说:

  

当别名发生时,不要使用子类化。

trait SocketFactory extends (SocketAddress => Socket)
     

SocketFactory是一个生成Socket的函数。使用类型   别名

type SocketFactory = SocketAddress => Socket
     

更好。我们现在可以为类型的值提供函数文字   SocketFactory还使用函数组合:       val addrToInet:SocketAddress => Long val inetToSocket:Long =>插座

val factory: SocketFactory = addrToInet andThen inetToSocket
     

请注意,类型别名不是新类型 - 它们等同于在语法上用别名替换其类型。

我们谈论的是:

trait Base
trait T1 extends Base // subclassing
type T2 = Base        // type alias

显然,当类/特征具有正文或存储信息时,您不能使用类型别名作为替换。

因此,使用类型别名(T2)而不是使用特征或类(T1)进行扩展具有以下优点:

  1. 如上所述,我们可以使用函数文字进行编写。
  2. 我们不会生成.class文件,编译器可以做的更少(理论上)。
  3. 但是,它有以下缺点:

    1. 要在同一名称空间(包)中可用,您需要在包对象中定义类型,该对象可能位于使用站点的另一个文件中。
    2. 你不能在Eclipse中的别名上跳转'Open Type'ctrl-shift-T,但你可以在Eclipse中打开声明(F3)。这可能会在将来修复。
    3. 您不能使用其他语言的类型别名,例如Java。
    4. 如果类型别名已参数化,则擦除会阻止模式匹配以与特征相同的方式工作。
    5. 第四点对我来说是最严重的:

      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
      

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

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

2 个答案:

答案 0 :(得分:8)

我认为他们的关键实际上是类型别名和特征真的不同。差异列表一直在继续:

  1. 速记语法适用于类型别名(例如x => x+7可用作type I2I = Int => Int)而不是特征。
  2. Traits可以携带额外的数据,类型别名不能。
  3. 暗示类型别名但不是特征。
  4. Traits以类型别名的方式提供类型安全/匹配。
  5. 类型别名有关于在子类中重写的严格规则;相反,相同的特征阴影(任何事情都有)。
  6. 等。

    这是因为在这两种情况下你做了截然不同的事情。类型别名只是一种说法,“好吧,当我输入Foo时,我实际上是指Bar。他们是相同的。知道了吗?很酷。”执行此操作后,您可以随时随地将Foo替换为Bar。唯一的限制是,一旦你决定了什么类型,你就无法改变主意

    另一方面,Traits创建了一个全新的界面,可以根据特征的扩展范围扩展,也可以不扩展。如果没有,那么仍然是一个标记,这是它自己的实体类型,可以进行模式匹配,使用'isInstanceOf'进行测试,依此类推。

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

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

答案 1 :(得分:2)

它们的不同之处在于类型别名定义了类型相等关系(即T1<:T2&& T1>:T2),而特征扩展定义了严格的子类型关系(即.T1<: T2&&!(T1>:T2))。明智地使用它们。