有什么不对? 为什么人是空的?
import org.scalacheck.{Arbitrary, Properties, Gen, Prop}
import Gen._
import Prop._
case class Person(name: String) {}
object QuickCheckPerson extends Properties("Person") {
property("gen1") = forAll { (person: Person) =>
println("person: " + person)
person.name == "john" // nullPointerException, because person == null
}
val john = Person("john")
implicit lazy val arbPerson: Arbitrary[Person] = Arbitrary(value(john))
}
QuickCheckPerson.check
它因NullPointerException而失败。
但是,如果我在val john = Person("john")
之前移动property("gen1") = ...
行,则该示例有效。
为什么?
更新
如果我将val john
声明为lazy
,则该示例有效。
所以,lazy val arbPerson
似乎在val john
之前执行,但如果是,
scala编译器应该失败,说john
没有定义。 john
是val
,也不是var
,因此要么声明也要实例化。
对此有何看法?
ps:scala 2.10.3
答案 0 :(得分:1)
所以,似乎la val val arbPerson在val之前执行 约翰,但如果是这样的话,斯卡拉编纂者应该失败说约翰是 没有定义的。 john是一个val,也不是var,所以它是声明的和 实例化或不实例化。
不,这不正确。 arbPerson
是一种内部方法,它执行双重检查锁定并懒惰地初始化私有字段。因为它是一个方法,所以可以从任何地方调用它,包括构造函数。你在这里所拥有的基本上是以下Java代码(当然,它无效,因为它是在这里写的,但它提供了基本的想法):
public class QuickCheckPerson extends Properties {
private final Person john;
private volatile Arbitrary<Person> arbPerson;
public QuickCheckPerson() {
super("Person"); // call superclass constructor
// property field belongs to superclass
property.update("gen1", forAll(new Function1<Person, Boolean>() {
/* closure implementation */
},
/* implicit parameter converting boolean to Prop */,
arbPerson(),
/* other implicits */
));
this.john = Person.apply("john");
}
public Arbitrary<Person> arbPerson() {
// Perform double-checked lock over a bit field (not presented here)
// and create arbPerson if needed
// Let's pretend that the following is double-checked lock:
if (arbPerson == null) {
arbPerson = Arbitrary.apply(value(john));
}
return arbPerson;
}
}
JVM中没有任何内容阻止您从构造函数中调用方法,这就是这里发生的事情。在arbPerson()
字段初始化之前调用john
方法(默认情况下,所有引用字段都为空),因此null
方法提供value()
。因此,您的NullPointerException
。
请告诉我扩展Scala代码是否有任何错误(或直接编辑帖子),我会修复它们。