2012-07-02 18 views
7

स्कैला में आलसी var बनाते हैं, स्काला को आलसी vars, केवल आलसी vals बनाने की अनुमति नहीं है। यह मतलब की बात है।स्कैला

लेकिन मैंने उपयोग मामले पर टक्कर लगी है, जहां मैं समान क्षमता रखना चाहता हूं। मुझे एक आलसी परिवर्तनीय धारक की जरूरत है। इसे एक मान असाइन किया जा सकता है जिसे समय लेने वाली एल्गोरिदम द्वारा गणना की जानी चाहिए। लेकिन बाद में इसे किसी अन्य मूल्य पर फिर से सौंप दिया जा सकता है और मैं पहले मूल्य गणना को कॉल नहीं करना चाहता हूं।

उदाहरण मानते हुए वहाँ कुछ जादू वर परिभाषा

lazy var value : Int = _ 
val calc1 :() => Int = ... // some calculation 
val calc2 :() => Int = ... // other calculation 
value = calc1 
value = calc2 
val result : Int = value + 1 

कोड का यह टुकड़ा केवल calc2() बुलाना चाहिए, calc1 नहीं

मेरे पास एक सुझाव है कि कैसे मैं अंतर्निहित रूपांतरण और के साथ इस कंटेनर में लिख सकते हैं है और विशेष कंटेनर वर्ग। मैं कलाकृतियां हूँ अगर कोई एम्बेडेड स्केला विशेषता यह है कि मुझे अनावश्यक कोड लिखने

उत्तर

1
var value:() => Int = _ 
lazy val calc1 = {println("some calculation"); 1} 
lazy val calc2 = {println("other calculation"); 2} 
value =() => calc1 
value =() => calc2 

scala> val result : Int = value() + 1 
other calculation 
result: Int = 3 
6

यह काम करता है की आवश्यकता नहीं है है:

var value:() => Int = _ 
val calc1:() => Int =() => { println("calc1"); 47 } 
val calc2:() => Int =() => { println("calc2"); 11 } 
value = calc1 
value = calc2 
var result = value + 1 /* prints "calc2" */ 

implicit def invokeUnitToInt(f:() => Int): Int = f() 

अंतर्निहित चिंता थोड़ा के बाद मुझे क्योंकि यह व्यापक रूप से लागू होता है, जो संदिग्ध implicits के बारे में अप्रत्याशित अनुप्रयोगों या कंपाइलर त्रुटियों का कारण बन सकता है।

lazy val calc3 = { println("calc3"); 3 } 
lazy val calc4 = { println("calc4"); 4 } 

class LazyVar[A] { 
    private var f:() => A = _ 
    def value: A = f() /* getter */ 
    def value_=(f: => A) = this.f =() => f /* setter */ 
} 

var lv = new LazyVar[Int] 
lv.value = calc3 
lv.value = calc4 
var result = lv.value + 1 /* prints "calc4 */ 
+0

दूसरा विकल्प – paradigmatic

+2

के लिए +1 यह एक सही समाधान के बाद से यह एक आलसी का "कैशिंग" प्रकृति पर कब्जा नहीं है नहीं है। अर्थात। हर बार जब आप lv.value का मूल्यांकन करते हैं तो फ़ंक्शन को फिर से निष्पादित किया जाएगा (इस उदाहरण में यह बार-बार प्रिंट करेगा)। –

1

खुद आप बस compilers कर सकता है काम करता है और इस तरह sth कार्य करें:



एक अन्य समाधान एक सेटर के साथ एक आवरण वस्तु और एक गेटर विधि है कि आप के लिए आलसी व्यवहार को लागू उपयोग कर रहा है:

class Foo { 
    private[this] var _field: String = _ 
    def field = { 
    if(_field == null) { 
     _field = "foo" // calc here 
    } 
    _field 
    } 

    def field_=(str: String) { 
    _field = str 
    } 
} 

scala> val x = new Foo 
x: Foo = [email protected] 

scala> x.field 
res2: String = foo 

scala> x.field = "bar" 
x.field: String = bar 

scala> x.field 
res3: String = bar 

संपादित करें: यह अपने धाराओं में धागा सुरक्षित नहीं है!

EDIT2:

MHS की दूसरी समाधान के लिए अंतर यह है कि गणना केवल एक बार, जबकि MHS के समाधान में इस पर कहा जाता है और फिर से है क्या होगा है।

0

यदि आप lazy val (इसे पथ-निर्भर प्रकारों और इसका धागा सुरक्षित में उपयोग किया जा सकता है) का उपयोग करना जारी रखना चाहते हैं, तो आप इसकी परिभाषा में संकेत की एक परत जोड़ सकते हैं (पिछले समाधान var एस को एक संकेत के रूप में उपयोग करते हैं):

lazy val value: Int = thunk() 
@volatile private var thunk:() => Int = .. 

thunk = ... 
thunk = ... 

यदि आप इसे पुन: उपयोग करना चाहते हैं तो आप इसे कक्षा में समाहित कर सकते हैं।

0

मैं कस्टम कंटेनर के निर्माण के लिए सभी उपलब्ध कराई गई सलाह का सारांश दिया है:

object LazyVar { 

    class NotInitialized extends Exception 

    case class Update[+T](update :() => T) 
    implicit def impliciţUpdate[T](update:() => T) : Update[T] = Update(update) 

    final class LazyVar[T] (initial : Option[Update[T]] = None){ 
    private[this] var cache : Option[T] = None 
    private[this] var data : Option[Update[T]] = initial 

    def put(update : Update[T]) : LazyVar[T] = this.synchronized { 
     data = Some(update) 
     this 
    } 
    def set(value : T) : LazyVar[T] = this.synchronized { 
     data = None 
     cache = Some(value) 
     this 
    } 
    def get : T = this.synchronized { data match { 
     case None => cache.getOrElse(throw new NotInitialized) 
     case Some(Update(update)) => { 
     val res = update() 
     cache = Some(res) 
     res 
     } 
    } } 

    def := (update : Update[T]) : LazyVar[T] = put(update) 
    def := (value : T) : LazyVar[T] = set(value) 
    def apply() : T = get 
    } 
    object LazyVar { 
    def apply[T](initial : Option[Update[T]] = None) = new LazyVar[T](initial) 
    def apply[T](value : T) = { 
     val res = new LazyVar[T]() 
     res.set(value) 
     res 
    } 
    } 
    implicit def geţLazy[T](lazyvar : LazyVar[T]) : T = lazyvar.get 

    object Test { 
    val getInt1 :() => Int =() => { 
     print("GetInt1") 
     1 
    } 
    val getInt2 :() => Int =() => { 
     print("GetInt2") 
     2 
    } 
    val li : LazyVar[Int] = LazyVar() 
    li := getInt1 
    li := getInt2 
    val si : Int = li 
    } 
}