Scala 斯卡拉虫?延迟与隐含
我发现使用和定义隐式值的行为(scala 2.9.1)非常奇怪,我想知道是否有人能解释它,或者这是scala的错误 我创建了一个独立的示例:Scala 斯卡拉虫?延迟与隐含,scala,Scala,我发现使用和定义隐式值的行为(scala 2.9.1)非常奇怪,我想知道是否有人能解释它,或者这是scala的错误 我创建了一个独立的示例: object AnnoyingObjectForNoPurpose { trait Printer[T] { def doPrint(v: T): Unit } def print[T : Printer](v: T) = implicitly[Printer[T]].doPrint(v) trait DelayedRunn
object AnnoyingObjectForNoPurpose {
trait Printer[T] {
def doPrint(v: T): Unit
}
def print[T : Printer](v: T) = implicitly[Printer[T]].doPrint(v)
trait DelayedRunner extends DelayedInit {
def delayedInit(x: => Unit){ x }
}
// this works, as it should
object Normal extends DelayedRunner {
implicit val imp = new Printer[Int] {
def doPrint(v: Int) = println(v + " should work")
}
print(343)
}
// this compiles, but it shouldn't
// and won't run, cause the implicit is still null
object FalsePositive extends DelayedRunner {
print(123)
implicit val imp = new Printer[Int] {
def doPrint(v: Int) = println(v + " should not compile")
}
}
def main(args: Array[String]) {
implicit val imp = new Printer[Int] {
def doPrint(v: Int) = println(v + " should work")
}
print(44)
// print(33.0) // correctly doesn't work
Normal // force it to run
FalsePositive // force this to run too
}
}
这和我写的是一样的错误:
object Foo {
println(x)
val x = 5
}
这不是虫子。构造函数沿着对象体向下流动,并按顺序进行<代码>延迟不是原因。这就是为什么在使用val/vars时需要小心,并确保它们首先初始化。这也是人们使用lazy val解决初始化顺序问题的原因。假设您将
delayInit
的定义更改为no op,即
def delayedInit(x: => Unit) { }
然后在你的主要方法中做一些类似的事情
println("FP.imp: " + FalsePositive.imp)
正如预期的那样,它将打印FP.imp:null
,但练习的真正目的是说明定义假阳性
主体的块的行为类似于常规类主体,而不是函数主体。它在看到val
时定义公共成员,而不是局部变量
如果像下面这样向烦扰对象添加了一个方法,它将无法编译,因为打印的隐式要求没有得到满足
def fails {
print(321)
implicit val cantSeeIt = new Printer[Int] {
def doPrint(v: Int) = println(v + " doesn't compile")
}
}
但是,如果您按照相同的原则定义了一个类,它将编译,但在初始化时会在运行时失败,就像您的false-positive
示例一样
class Fine {
print(321)
implicit val willBeNull = new Printer[Int] {
def doPrint(v: Int) = println(v + " compiles, but fails")
}
}
需要明确的是,Fine
的编译行为与隐式
的存在无关。类/对象初始值设定项非常乐意使用引用未定义的val
s的val
初始值设定项进行编译
object Boring {
val b = a
val a = 1
println("a=%s b=%s".format(a, b))
}
Boring
编译得很好,当引用它时,它会打印a=1 b=0
您的问题似乎可以归结为“从DelayedInit
派生的类/对象的主体是否应该像编译类主体或函数块一样进行编译?”
看起来奥德斯基选择了前者,但你希望是后者。我觉得很困惑,你在def print(第7行)中重用T作为标识符,这导致了一个问题,隐式[Printer[T]]
是打印机的隐式打印机吗?不同的标识符是否有助于避免混淆?@userunknown我不太清楚你的意思,或者更简单的书写方式?你能更具体地回答你的问题吗?你说“这是编译,但不应该”,但这是一个陈述,不是一个问题。你的问题是什么?