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

ade*_*rtc 2 inheritance scala multiple-inheritance traits

所以我正在为不耐烦的书阅读Scala,它使用的一个例子是一个Logger基本上打印String到某个流的特征.在该实例中,它具有性状ConsoleLogger(延伸Logger),该打印消息出去stdoutShortLogger(也延伸Logger),其简单地截断字符串,如果该长度过长.要改变ShortLogger书籍的最大长度,建议使用匿名子类,如:

val acct = new SavingsAccount with ConsoleLogger with ShortLogger {
  val maxLength = 20
}
Run Code Online (Sandbox Code Playgroud)

ShortLogger具有抽象maxLength: Int字段的特征在哪里SavingsAccount定义为

class SavingsAccount extends Account with Logged { ... }
Run Code Online (Sandbox Code Playgroud)

这对我有意义(有点).我假设施工顺序是:

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

然而,在本书的后面,它给出了一个新的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
}
Run Code Online (Sandbox Code Playgroud)

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

val acct = new {
  val filename: "myapp.log"
} with SavingsAccount with FileLogger
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*ral 5

你的施工顺序是完全错误的.:-)

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

所以:

  1. 帐户
  2. 记录
  3. SavingsAccount
  4. ConsoleLogger
  5. ShortLogger
  6. 匿名子类

现在,问你的问题:

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

val acct = new {
  val filename: "myapp.log"
} with SavingsAccount with FileLogger
Run Code Online (Sandbox Code Playgroud)

请注意,代码块在第二个示例中排在第一位.这就是所谓的早期初始化,它的作用是在其他任何事情之前应用该初始化.