scalacheck生成器生成一个空样本

时间:2013-11-14 22:08:07

标签: scala scalacheck

有什么不对? 为什么人是空的?

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没有定义。 johnval,也不是var,因此要么声明也要实例化。

对此有何看法?

ps:scala 2.10.3

1 个答案:

答案 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代码是否有任何错误(或直接编辑帖子),我会修复它们。