所以我正在阅读Scala for the Impatient书,其使用的一个示例是Logger
特征,它基本上将String
打印到某个流。在示例中,它有一个特征ConsoleLogger
(扩展Logger
),可以将消息打印到stdout
和ShortLogger
(也扩展为Logger
)如果长度太长,则截断字符串。要更改本书建议的ShortLogger
的最大长度,请使用匿名子类,如:
val acct = new SavingsAccount with ConsoleLogger with ShortLogger {
val maxLength = 20
}
其中ShortLogger
是具有抽象maxLength: Int
字段的特征,SavingsAccount
定义为
class SavingsAccount extends Account with Logged { ... }
这对我有意义(有点)。我假设施工订单是:
Logger
(因为它是ConsoleLogger
的超级特征),ConsoleLogger
ShortLogger
Account
SavingsAccount
。 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
}
它说由于施工顺序它不起作用。他们建议修改:
val acct = new {
val filename: "myapp.log"
} with SavingsAccount with FileLogger
但是,这个定义似乎与上面maxLength
的定义相似,那么我在上面的例子和底部例子之间缺少什么?
答案 0 :(得分:5)
您的施工顺序完全错误。 : - )
要构建的第一件事是课程,然后你从左到右经历这些特征。它有点复杂 - 有线性化规则可以处理多次遗传的特征,但这就是它。
所以:
现在,问你的问题:
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,它的作用是在其他任何事情之前应用该初始化。