2012-08-29 10 views
18

संभव डुप्लिकेट:
Scala: forward references - why does this code compile?स्काला और आगे संदर्भ

object Omg { 

    class A 

    class B(val a: A) 

    private val b = new B(a) 

    private val a = new A 

    def main(args: Array[String]) { 
    println(b.a) 
    } 

} 

निम्नलिखित कोड प्रिंट "अशक्त"। जावा में इसी तरह के निर्माण अमान्य आगे संदर्भ के कारण संकलित नहीं है। सवाल यह है - यह स्कैला में अच्छी तरह से संकलित क्यों होता है? क्या यह डिज़ाइन द्वारा एसएलएस में वर्णित है या बस 2.9.1 में बग है?

+1

मुद्दा यह है कि मुझे गुस्सा दिलाती है के बारे में यह है कि यह एक वैल अपने मूल्य बदलने की अनुमति देता है। इससे मुझे दुःख होता है :-( – thoredge

+0

यह थोड़ा अजीब है - इसके द्वारा बहुत सी त्रुटि हो सकती है, और मैंने जावा व्यवहार पर भरोसा किया, जिसके लिए उपयोग किए जाने से पहले मूल्यों को प्रारंभ करने की आवश्यकता होती है। – jdevelop

+1

@jdevelop यहां तक ​​कि जावा सभी को नहीं पकड़ता संभावित आगे संदर्भ। –

उत्तर

23

यह एक बग नहीं है, लेकिन स्कैला सीखते समय एक क्लासिक त्रुटि है। जब ऑब्जेक्ट Omg प्रारंभ होता है, तो सभी मान पहले इस मान में डिफ़ॉल्ट मान (null) पर सेट होते हैं और फिर कन्स्ट्रक्टर (यानी ऑब्जेक्ट बॉडी) चलता है।

object Omg { 

    class A 

    class B(val a: A) 

    private val b = new B(a) 

    private lazy val a = new A 

    def main(args: Array[String]) { 
    println(b.a) 
    } 
} 

मूल्य a तो मांग पर प्रारंभ किया जाएगा:

यह काम, बस (इस मामले में मूल्य a) घोषणा आप आगे संदर्भित कर रहे हैं के सामने lazy कीवर्ड जोड़ने के बनाने के लिए।

यह निर्माण तेज़ है (मान केवल सभी एप्लिकेशन रनटाइम के लिए प्रारंभ किए जाते हैं) और थ्रेड-सुरक्षित।

+11

'आलसी' काम जोड़ना यदि आप जानते हैं * आप गलत क्रम में बयान निष्पादित कर रहे हैं। लेकिन यदि आप * सोचते हैं * आपके पास सही क्रम में है, तो आप शायद "अनावश्यक" आलसी 'जोड़ने के बारे में नहीं सोचेंगे। : / – kornfridge

2

@paradigmatic राज्यों के रूप में, यह वास्तव में एक बग नहीं है। यह प्रारंभिक आदेश है, जो घोषणा आदेश का पालन करता है। यह मामला, a शून्य है जब b घोषित/init-ed है।

private val b = new B(a) से private lazy val b = new B(a) पर लाइन को बदलना समस्या को ठीक करेगा, क्योंकि आलसी उपयोग करने से इनिट में देरी होगी। बी के पहले उपयोग के लिए।

यह बहुत संभावना है कि एसएलएस में यह व्यवहार वर्णित है।

7

जिस तरह से मैं इसे समझता हूं, इसे स्केल कक्षाओं के निर्माण के तरीके के साथ करना है। जावा में, ऊपर परिभाषित कक्षा वैरिएबल इनलाइन शुरू कर देगी, और चूंकि a अभी तक परिभाषित नहीं किया गया था, इसे संकलित नहीं किया जा सका। हालांकि, स्काला में इसे और अधिक जावा में इस के बराबर (जो भी एक ही स्थिति में अशक्त उत्पादन चाहिए) है:

class Omg { 
    private B b = null; 
    private A a = null; 

    Omg(){ 
    b = new B(a); 
    a = new A(); 
    } 
} 

वैकल्पिक रूप से, आप b आलसी की अपनी घोषणा है, जो जब तक मान सेट स्थगित होगा बना सकता है इसे कहा जाता है (उस समय एक इच्छा निर्धारित की जाएगी)।

6

यदि यह चिंता है, तो अपवाद दूर होने तक विकास और पुनरावृत्ति के दौरान -Xcheckinit के साथ संकलित करें।

आदेश में निष्पादित टेम्पलेट बॉडी स्टेटमेंट्स के लिए स्पेक 5.1; ब्लॉक में आगे संदर्भ के लिए 4.0 की शुरुआत।

Forward References - why does this code compile?