2016-12-10 73 views
1

分配變量一旦這就是我想做的事 -斯卡拉:無VAL

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

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

在這種特定的情況下,方法1和2是互斥的,它們中的一個在一個生命週期調用一次A.的實例。另外,v被賦值一次。我寧願讓它成爲一個val。但是因爲我需要method2或method3的上下文來初始化v,所以我不能在構造函數中這樣做。

如何實現這種「val」行爲?我可以考慮修改method1和method2來應用方法,但我不喜歡這個想法。此外,方法1和方法2具有相同的參數簽名(因此應用程序需要一些更多的信息來區分兩種類型的調用)。

+1

爲什麼'v'值不能作爲參數傳遞給'm3'? 'm3'是從'class'之外調用的嗎?如果是這樣,可以在'm1'或'm2'之前調用'm3'嗎? (這聽起來像是一個設計缺陷。) – jwvh

+0

對我來說聽起來像你只需要強制執行'method1'或'method2'只能調用一次,'method3'只能在事後調用。 –

+0

@jwvh m3是一個私有方法,應該在我的代碼片段中提到。 – anindyaju99

回答

7

一個重要的問題是:你究竟稱爲「val行爲」?對我來說,「val行爲」是在聲明時立即分配一次,可以靜態強制執行。您似乎想強制執行v未分配兩次。在分配之前,您可能還想強制執行它從不是讀取。您可以爲創建一個非常小幫手箱:

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() 
    } 
} 

哦,並且只是在開玩笑,但Ozma具有內置:-P

單賦值瓦爾斯
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