2016-12-10 10 views
1

せずに一度変数を割り当てる - この特定のケース法1と2ではスカラ:これは私が何をしたいですヴァル

class A(some args) { 
    var v: SomeType = null 
    def method1(args) = { 
    v = something1 
    ... 
    method3 
    } 

    def method2(args) = { 
    v = something2 
    ... 
    method3 
    } 
    def method3 = { 
    // uses v 
    } 
} 

は相互に排他的であり、それらのいずれかがANの一生に1回だけ呼び出されますまた、vは一度代入されます。私はそれを価値にすることを好むだろう。しかし、私はvを初期化するためにmethod2またはmethod3のコンテキストが必要なので、私はコンストラクタでそれを行うことはできません。

どのようにこの「val」動作を達成できますか? method1とmethod2を変更してメソッドを適用すると思いますが、私はその考えが気に入らないのです。さらに、method1と2は同じ引数シグニチャを持っています(したがって、2種類の呼び出しを区別するためにはさらに多くの情報が必要です)。

+1

なぜ「v」値を「m3」の引数として渡せないのですか? 'm3'は' class'の外側から呼び出されていますか?もしそうなら、 'm1'または' m2'の前に 'm3'を呼び出すことができますか? (これは設計上の瑕疵のようです) – jwvh

+0

'method1'や' method2'は一度しか呼び出せないし、 'method3'は後でしか呼び出せないように強制する必要があります。 –

+0

@jwvh m3はプライベートメソッドです、私のスニペットでそれを述べたはずです。 – anindyaju99

答えて

7

重要な質問は次のとおりです。「ヴァルの行動」とは具体的に何ですか?私には、「valの振る舞い」は、それが宣言されたときすぐに一度割り当てられ、それは静的に強制することができます。 vが2回割り当てられていないことを強制したいようです。場合によっては、それが割り当てられる前にと読み取られることは決してありません。あなたはそのために非常に小さなヘルパーボックスを作成することができます。

final class OnceBox[A] { 
    private[this] var value: Option[A] = None 

    def update(v: A): Unit = { 
    if (value.isDefined) 
     throw new IllegalStateException("Value assigned twice") 
    value = Some(v) 
    } 

    def apply(): A = { 
    value.getOrElse { 
     throw new IllegalStateException("Value not yet assigned") 
    } 
    } 
} 

、今スニペット:

class A(some args) { 
    val v = new OnceBox[SomeType] 
    def method1(args) = { 
    v() = something1 
    ... 
    method3 
    } 

    def method2(args) = { 
    v() = something2 
    ... 
    method3 
    } 
    def method3 = { 
    // uses v 
    v() 
    } 
} 

ああと、冗談が、内蔵された:-P

シングル割り当てヴァルスを Ozmaあり
3

多分このような何か:

class A private (mtdType: Int, ...) { 
     val v = mdtType match { 
     case 1 => method1(...) 
     case 2 => method2(...) 
     } 
    } 


    object A { 
    def withMethod1(...) = new A(1, ...) 
    def withMethod2(...) = new A(2, ...) 
    } 

あるいは、別のpossibilty:

sealed trait A { 
    val v 
    def method3 = println(v) 
    } 

    class Method1(...) extends A { 
     val v = method1(...) 
    } 

    class Method2(...) extends A { 
     val v = method2(...) 
    } 
5

サブタイプではなく、他の回答と同様の考え方です。

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

class A { 
    private[this] var context: Int = _ 
    lazy val v: String = 
    context match { 
     case 1 => "one" 
     case 2 => "two" 
     case _ => ??? 
    } 
    def m1() = { context = 1 ; v } 
    def m2() = { context = 2 ; v } 
} 

// Exiting paste mode, now interpreting. 

defined class A 

scala> val a = new A 
a: A = [email protected] 

scala> a.m2 
res0: String = two 

scala> a.m1 
res1: String = two 
+0

'v'はコンテキストが設定されるまでスローし、通常通り動作します。 –

+0

私はこの考え方を早く考えました。しかし、私の特定のユースケースの問題は複雑な初期化(m1とm2で計算される多くの変数)です。したがって、コンテキストは値のセットでなければなりません(必要なフィールドを持つクラスかもしれません)。もちろん、私はこのアプローチを拡張することができ、-vとコンテキストは同じ型であり、同じオブジェクトにも結果が割り当てられると言います。しかし、これは、コンテキストの代わりにvを使う未来の開発者を強制するにはあまりにも複雑です。 – anindyaju99

関連する問題