3

関連する問題に対処する複数の質問があることは知っていますが、探しているものを正確に攻撃するかどうかはわかりません. 数年間 Java 開発を行ってきた私は、まだ Scala に慣れていません。オブジェクトが初期化されているかどうかをテストし、そうでない場合は初期化する最良の方法を探しています。たとえば、Java では次のようになります。

private MyObject myObj = null;

そして将来のある時点で:

public void initMyObj(){
    if (myObj == null){
        myObj = new MyObj();
    }
    // do something with myObj
}

この後、myObj を別のオブジェクトに再割り当てするかもしれませんが、そうはなりません。Scalaでは、私はこれを持っています:

class Test {
    var myObj: MyObj = _
}

代わりに Option を使用できることを読みました。

var myObj = None : Option[MyObj]

そして私のチェック:

myObj match {
  case None => ...
  case Some(value) => ...
}

しかし、私がこの種のチェックを他のどこでも行うことがないかもしれないときに、このパターンを使用するのは気が進まない. これは私が望むものを達成するための最良の方法ですか、それともオプションを含まない他のオプションはありますか?

4

2 に答える 2

5

おそらく、遅延変数が必要です。

lazy val myObj: MyObj = //here you put the object creation code

このようにして、オブジェクトの作成は、コードが最初にアクセスを試みるまで延期されます。

于 2013-01-18T15:52:40.973 に答える
5

部分的に構築されたオブジェクトをそのままにしておくことは、Scala では一般的に理想的な方法ではありません。通常、オブジェクトがインスタンス化される方法を再考して、壊れにくい別のパターンを使用できないかどうかを確認します。たとえば、メソッドで初期化されていない変数を設定する代わりに、次のようにします。

class Foo { var a: String = null; var b: String = null }
def initFooA(s: String, f: Foo) { if (f.a == null) f.a = s }
def initFooB(s: String, f: Foo) { if (f.b == null) f.b = s }
f
initFooA("salmon", f)
// Do stuff
initFooB("herring", f)

コードを再構築して必要な値をオンデマンドで生成しようとし、それまで foo のインスタンス化を遅らせます。

case class Bar(a: String, b: String) {}
def initBarA(s: String) = s
def initBarB(s: String) = s
val iba = initBarA("halibut")
// Do stuff
val ibb = initBarB("cod")
Bar(iba, ibb)

Scala はタプル (および型推論) に簡単にアクセスできるため、これは Java よりもはるかに簡単です。

あなたができるもう一つのことは、遅い初期化を他の人に任せることです。

case class Baz(a: String)(bMaker: => String) {
  lazy val b = bMaker
}

ここで、パラメータ b を作成する何かを渡し、処理が必要な後期初期化処理を処理するように手配します。これは常に vars を設定する必要を回避するわけではありませんが、クラス コードから初期化ロジックにプッシュするのに役立ちます (通常は、変数を設定するのに適した場所です)。

これを vars で行うのは少し簡単ではありません。現実的には、クラスをそれに専念させるのがおそらく最善の方法です。たとえば、次のようにします。

class LazyVar[A](initial: => A) {
  private[this] var loaded = false
  private[this] var variable: A = _
  def apply() = { if (!loaded) { loaded = true; variable = initial }; variable }
  def update(a: A) { loaded = true; variable = a }
}

次に、(悲しいことに)()読み取りと書き込みのたびに使用する必要があります。

scala> val lv = new LazyVar({ println("Hi!"); 5 })
lv: LazyVar[Int] = LazyVar@2626ea08

scala> lv()
Hi!
res2: Int = 5

scala> lv() = 7

scala> lv()
res4: Int = 7

次に、実際のクラスの代わりにこのクラスのインスタンスを使用varし、遅延初期化子を渡します。(lazy val内部はこれと非常によく似ています。コンパイラは、ユーザーが気付かないように保護しているだけです。)

最後に、時々値が欠落している完全に機能するオブジェクトが必要な場合var x: Option[X]は、使用したい構造です。標準の Java 作成パターンを回避する方法が見つからない場合 (そして、パフォーマンスが重要であり、それを行う余裕がないため、より多くの情報を使用して相互に作成するオブジェクトのような、より風変わりなものを試したくない場合) 、または型チェックでオブジェクトが適切に作成されていることを確認できるようにするためにボイラープレートをそれほど多く書くのは嫌いですが、それ以外の場合はそれを使用したいので、var x: X = null私はそれを選択し、 ではありません_。がプリミティブである場合Xは、とにかく適切な値を賢明に選択する必要があります (たとえば、 for ではなくの代わりDouble.NaN0.0-10Int) は、私が初期化されていないことを示します。それが一般的なコードであり、 の代わりに が必要な場合は、Anyとの間を-ing で行ったり来たりすることが、型チェックが不十分な状況から抜け出すためのおそらく最良の方法です (実際には を使用できないと仮定すると、その時点でより明確になります)。AnyRefasInstanceOfAnyAnyRefOption

于 2013-01-18T16:22:06.903 に答える