2012-04-15 23 views
5

में आलसी vals और अंतर्निहित पैरामीटर मैं स्कैला में अंतर्निहित पैरामीटर कैसे काम करता है इस पर एक समझने की कोशिश कर रहा हूं। जहां तक ​​मैं निहित पैरामीटर रिज़ॉल्यूशन बता सकता हूं, इस तरह कुछ जाता है:स्कैला

  1. स्पष्ट रूप से विधि को ऑब्जेक्ट पास कर रहा है।
  2. दायरे में परिभाषित अंतर्निहित परिभाषाएं।
  3. एक अंतर्निहित पैरामीटर

हालांकि के रूप में इस्तेमाल वर्ग के साथी वस्तु, जब मैं संयोजन के रूप आलसी Vals में इस के साथ प्रयोग करना शुरू कर दिया मैं एक supprise का एक सा हो गया। ऐसा लगता है कि आलसी vals केवल अंतिम संकल्प नियमों का उपयोग करें। यहां कुछ नमूना कोड उदाहरण देकर स्पष्ट करने के लिए है:

Case 1: with implicitp parameter from companion object 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'some default bar' ... 
Case 2: with mixedin implicit parameter overriding the default one... 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'mixed in implicit bar'... 
Case 3: with local implicit parameter overriding the default one... 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'locally scoped implicit bar' ... 

संकलक क्यों पकड़ नहीं करता है एक implict बार जब स्थिति 2 में mixedInList बुला में मिश्रित है कि वहाँ:

class Bar(val name:String) 
object Bar { implicit def bar = new Bar("some default bar") } 

class Foo { 
    lazy val list = initialize 
    def initialize(implicit f:Bar) = { 
    println("initialize called with Bar: '" + f.name + "' ...") 
    List[Int]() 
    } 
} 

trait NonDefaultBar extends Foo { 
    implicit def f = new Bar("mixed in implicit bar") 
    def mixedInInit = initialize 
    lazy val mixedInList = list 
} 

object Test { 
    def test = { 
     println("Case 1: with implicitp parameter from companion object") 
     val foo1 = new Foo 
     foo1.list 
     foo1.initialize 

     println("Case 2: with mixedin implicit parameter overriding the default one...") 
     val foo2 = new Foo with NonDefaultBar 
     foo2.mixedInList 

     val foo3 = new Foo with NonDefaultBar 
     foo3.mixedInInit 

     println("Case 3: with local implicit parameter overriding the default one...") 
     implicit def nonDefaultBar = new Bar("locally scoped implicit bar") 
     val foo4 = new Foo 
     foo4.list 
     foo4.initialize 
    } 
} 

Test.test कॉलिंग निम्नलिखित उत्पादन देता है। केस 3 में यह सूची तक पहुंचने पर स्थानीय रूप से परिभाषित अंतर्निहित बार को भी याद करता है।

आलसी vals के साथ अंतर्निहित पैरामीटर का उपयोग करने के कोई तरीके हैं जो साथी ऑब्जेक्ट में परिभाषित अंतर्निहित उपयोग का उपयोग नहीं करते हैं?

उत्तर

4

ऐसा इसलिए है क्योंकि कोई अन्य implicit Bar नहीं है, जब संकलक Foo क्लास को संकलित करता है। जावा में decompiled कोड ऐसा दिखाई:

public class Foo 
    implements ScalaObject 
{ 
    private List<Object> list; 
    public volatile int bitmap$0; 

    public List<Object> list() 
    { 
    if (
     (this.bitmap$0 & 0x1) == 0); 
    synchronized (this) 
    { 
     if (
     (this.bitmap$0 & 0x1) == 0) { 
     this.list = initialize(Bar..MODULE$.bar()); this.bitmap$0 |= 1; } return this.list; 
    } 
    } 
    public List<Object> initialize(Bar f) { Predef..MODULE$.println(new StringBuilder().append("initialize called with Bar: '").append(f.name()).append("' ...").toString()); 
    return Nil..MODULE$; 
    } 
} 

lazy val सिर्फ एक विधि है, तो चर पहले से ही सेट किया गया है की जाँच करता है कि है और या तो यह लौटाता है, या यह सेट और फिर इसे वापस आती है। तो आपका मिश्रण बिल्कुल ध्यान में नहीं लिया जाता है। यदि आप इसे चाहते हैं, तो आपको खुद को प्रारंभिकरण का ख्याल रखना होगा।

+0

ठीक है, लेकिन * यह * implicits पहचान नहीं होना चाहिए? वे संकलन समय पर सही हैं? अगर मैं कन्स्ट्रक्टर को अंतर्निहित पैरामीटर ले जाऊं तो शायद यह काम करेगा? –

+0

यह केवल एकमात्र अंतर्निहित बार को पहचानता है जो संकलन समय पर गुंजाइश है, और यह बार साथी में से एक है। क्योंकि 'सूची' केवल' फू 'पर परिभाषित है, यह हमेशा इसका उपयोग करेगा। आप अपने कन्स्ट्रक्टर में अंतर्निहित परिभाषित कर सकते हैं, लेकिन विशेषता में निहित अभी भी दायरे में नहीं होगा, क्योंकि यह केवल उदाहरण पर मौजूद है। – drexin

+0

तो यदि मैं आलसी वैल को स्थानांतरित करता हूं और 'NonDefaultBar' विशेषता के लिए विधि प्रारंभ करता हूं और उस विशेषता को' Foo 'तक बढ़ाता है और अंतर्निहित डीफ़ को' Foo 'पर ले जाता है, तो मैं संकलक को' Foo 'में निहित डीफ़ को पकड़ने के बारे में जानूंगा 'आलसी मूल्य सूची' का मूल्यांकन करते समय? –

0

हालांकि स्कैला अंतर्निहित पैरामीटर के साथ आलसी vals का समर्थन नहीं करता है, आप इसे स्वयं विकल्पों का उपयोग करके परिभाषित कर सकते हैं।

द्वारा

lazy val list = initialize 

private var _list: Option[List[Int]] = None 
def list(implicit f: Bar) = 
    _list.getOrElse{ 
    _list = Some(initialize) 
    _list.get 
    } 

फिर Test.test प्रदर्शित करता है अपेक्षित परिणाम चल:

Case 1: with implicitp parameter from companion object 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'some default bar' ... 
Case 2: with mixedin implicit parameter overriding the default one... 
initialize called with Bar: 'mixed in implicit bar' ... 
initialize called with Bar: 'mixed in implicit bar' ... 
Case 3: with local implicit parameter overriding the default one... 
initialize called with Bar: 'locally scoped implicit bar' ... 
initialize called with Bar: 'locally scoped implicit bar' ... 

ध्यान दें कि अगर आप mutable options था, तो आप अपने आलसी बदल सकते इसलिए, एक समाधान को बदलने के लिए है एक ही परिणाम प्राप्त करने के लिए केवल दो लाइनों के साथ वैल।

private val _list: MutableOpt[List[Int]] = MutableOpt.from(None) 
def list(implicit f: Bar) = _list.getOrSet(initialize) 

व्यक्तिगत रूप से, मैं एक दिन आशा है कि स्काला हमें इस एक लाइन का उपयोग लिखने दूँगी:

lazy val list(implicit f: Bar) = initialize 

जो पूरी तरह से सार्थक होगा: किसी भी समय आप चर सूची के मूल्य में उपयोग करना चाहते पर, आपको दायरे में एक बार की जरूरत है, हालांकि केवल पहली गणना ही मायने रखती है।