0

なにが問題ですか?なぜ人はnullですか?

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 johnasを宣言すると、この例は機能しlazyます。lazy val arbPersonそのため、 が の前に実行されているように見えますが、そうであれば、scala コンパイラはそれが定義されていないval johnと言って失敗するはずです。もでもないので、宣言されてインスタンス化されているかどうかのどちらかです。johnjohnvalvar

これについて何か考えはありますか?

PS: スカラ 2.10.3

4

1 に答える 1

1

そのため、怠惰な val arbPerson が val john の前に実行されているように見えますが、そうであれば、scala コンパイラは john が定義されていないと言って失敗するはずです。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 である) ため、メソッドnullに提供されvalue()ます。したがって、あなたのNullPointerException.

私の Scala コードの展開に間違いがあれば教えてください (または投稿を直接編集してください)。修正します。

于 2013-11-15T10:35:42.537 に答える