在特征(Scala)的抽象领域 - 建筑顺序

时间:2012-07-04 21:21:00

标签: scala inheritance multiple-inheritance traits

所以我正在阅读Scala for the Impatient书,其使用的一个示例是Logger特征,它基本上将String打印到某个流。在示例中,它有一个特征ConsoleLogger(扩展Logger),可以将消息打印到stdoutShortLogger(也扩展为Logger)如果长度太长,则截断字符串。要更改本书建议的ShortLogger的最大长度,请使用匿名子类,如:

val acct = new SavingsAccount with ConsoleLogger with ShortLogger {
  val maxLength = 20
}

其中ShortLogger是具有抽象maxLength: Int字段的特征,SavingsAccount定义为

class SavingsAccount extends Account with Logged { ... }

这对我有意义(有点)。我假设施工订单是:

    首先构建
  1. Logger(因为它是ConsoleLogger的超级特征),
  2. ConsoleLogger
  3. ShortLogger
  4. Account
  5. SavingsAccount
  6. 然后我们有匿名子类构造,我们定义了抽象maxLength = 20
  7. 然而,在本书后面,它给出了一个新的Logger子特征:

    trait FileLogger extends Logger {
      val filename: String
      val out = new PrintStream(filename)
      def log(msg: String) { out.println(msg); out.flush() }
    }
    
    val acct = new SavingsAccont with FileLogger {
      val filename = "myapp.log" // Does not work
    }
    

    它说由于施工顺序它不起作用。他们建议修改:

    val acct = new {
      val filename: "myapp.log"
    } with SavingsAccount with FileLogger
    

    但是,这个定义似乎与上面maxLength的定义相似,那么我在上面的例子和底部例子之间缺少什么?

1 个答案:

答案 0 :(得分:5)

您的施工顺序完全错误。 : - )

要构建的第一件事是课程,然后你从左到右经历这些特征。它有点复杂 - 有线性化规则可以处理多次遗传的特征,但这就是它。

所以:

  1. 帐户
  2. 已记录
  3. SavingsAccount
  4. ConsoleLogger
  5. ShortLogger
  6. 匿名子类
  7. 现在,问你的问题:

    val acct = new SavingsAccont with FileLogger {
      val filename = "myapp.log" // Does not work
    }
    
    val acct = new {
      val filename: "myapp.log"
    } with SavingsAccount with FileLogger
    

    请注意,代码块在第二个示例中排在第一位。这被称为early initialization,它的作用是在其他任何事情之前应用该初始化。