2012-03-31 12 views
10

मैं कोड ब्लॉक में रिक्त रूप से एक चर परिभाषित क्यों नहीं कर सकता?मैं कोड ब्लॉक में रिक्त रूप से एक चर परिभाषित क्यों नहीं कर सकता?

scala> { 
    | val test: Stream[Int] = 1 #:: test 
    | } 
<console>:9: error: forward reference extends over definition of value test 
       val test: Stream[Int] = 1 #:: test 
              ^

scala> val test: Stream[Int] = 1 #:: test 
test: Stream[Int] = Stream(1, ?) 

lazy कीवर्ड इस समस्या का हल है, लेकिन मैं नहीं समझ सकता क्यों यह एक कोड ब्लॉक के बिना काम करता है, लेकिन एक कोड ब्लॉक में एक संकलन त्रुटि फेंकता है।

उत्तर

23

ध्यान दें कि आरईपीएल में

scala> val something = "a value" 

मूल्यांकन किया जाता है और अधिक या कम इस प्रकार है:

object REPL$1 { 
    val something = "a value" 
} 
import REPL$1._ 

तो, किसी भी val (या def, आदि) एक आंतरिक आरईपीएल सहायक ऑब्जेक्ट का एक सदस्य है ।

object ForwardTest { 
    def x = y // val x would also compile but with a more confusing result 
    val y = 2 
} 
ForwardTest.x == 2 

यह एक ब्लॉक के अंदर val रों लिए सही नहीं है:

अब मुद्दा यह है कि वर्गों (और वस्तुओं) आगे संदर्भ की अनुमति देने के अपने सदस्यों पर है। एक ब्लॉक में सब कुछ रैखिक क्रम में परिभाषित किया जाना चाहिए। इस प्रकार val एस अब कोई सदस्य नहीं हैं लेकिन सादे चर (या मान, resp।) हैं। निम्नलिखित संकलित नहीं है:

def plainMethod = { // could as well be a simple block 
    def x = y 
    val y = 2 
    x 
} 

<console>: error: forward reference extends over definition of value y 
    def x = y 
      ^

यह रिकर्सन नहीं है जो अंतर बनाता है। अंतर यह है कि कक्षाएं और वस्तुएं आगे संदर्भों की अनुमति देती हैं, जबकि ब्लॉक नहीं करते हैं।

2

इस व्यवहार का कारण विभिन्न वैल प्रारंभिक समय पर निर्भर करता है। यदि आप val x = 5 सीधे आरईपीएल पर टाइप करते हैं, तो x किसी ऑब्जेक्ट का सदस्य बन जाता है, जिसे मान डिफ़ॉल्ट मान (शून्य, 0, 0.0, झूठी) के साथ प्रारंभ किया जा सकता है। इसके विपरीत, ब्लॉक में मान डिफ़ॉल्ट मानों से प्रारंभ नहीं हो सकते हैं।

यह अलग व्यवहार करता है:

scala> class X { val x = y+1; val y = 10 } 
defined class X 

scala> (new X).x 
res17: Int = 1 

scala> { val x = y+1; val y = 10; x } // compiles only with 2.9.0 
res20: Int = 11 

स्काला 2.10 में पिछले उदाहरण अब और संकलन नहीं है। 2.9.0 में संकलन को संकलित करने के लिए संकलक द्वारा मानों को पुन: व्यवस्थित किया जाता है। एक bug report है जो विभिन्न प्रारंभिक समयों का वर्णन करता है।

+0

अंतिम उदाहरण संकलित नहीं करता है। (निश्चित रूप से प्रश्न में पूरा बिंदु है।) – Debilski

+0

@ डेबिलस्की: आप सही हैं, 2.10 के साथ यह अब संकलित नहीं होता है। मैंने बग रिपोर्ट में उल्लिखित संकलन के लिए 2.9.0 का उपयोग किया। – sschaef

+0

मैं 2.9.1-1 का उपयोग कर रहा था। तो यह बीच में बदल दिया जाना चाहिए। – Debilski

4

मैं जोड़ देंगे कि जब आप लिखते हैं:

object O { 
    val x = y 
    val y = 0 
} 

आप वास्तव में यह लिख रहे हैं:

object O { 
    val x = this.y 
    val y = 0 
} 

थोड़ा this जब आप एक परिभाषा के अंदर इस सामग्री की घोषणा क्या याद आ रही है है कि।

0

मैं यह जोड़ना चाहता हूं कि एक्लिप्स-आधारित स्कैला-आईडीई (v4.0.0) में स्कैला वर्कशीट आरईपीएल की तरह व्यवहार नहीं करती है, जैसा कि कोई उम्मीद कर सकता है (उदाहरण के लिए https://github.com/scala-ide/scala-worksheet/wiki/Getting-Started कहता है "वर्कशीट स्टेरॉयड पर एक आरईपीएल सत्र की तरह हैं ") इस संबंध में, बल्कि एक लंबी विधि की परिभाषा की तरह: यही है, वर्कशीट में वाल परिभाषाओं (रिकर्सिव वैल परिभाषाओं सहित) का संदर्भ देना कुछ ऑब्जेक्ट या क्लास के सदस्य बनना चाहिए।

संबंधित मुद्दे

 संबंधित मुद्दे