2010-07-28 2 views
5

मुझे अपने स्कैला कोड में एक त्रुटि मिली, जो मुझे पहेली करता है। नीचे समस्या का एक सरलीकृत संस्करण है।स्काला अमूर्त विधि सुपरक्लास में शून्य है जब सबक्लास इसे वैल का उपयोग करके लागू करता है?

एक अमूर्त वर्ग के निर्माता में, मैं अमूर्त तरीकों के बारे में कुछ आवेषण देखना चाहता हूं। इस प्रकार जब सबक्लास का ऑब्जेक्ट किया जाता है, तो ये आवेषण चेक किया जाता है, यह देखने के लिए कि क्या सभी को इसे लागू किया जाना चाहिए या नहीं।

यह गलत हो जाता है जब उपवर्ग एक सार विधि एक "वैल" का उपयोग तथापि लागू करता है:

स्काला कोड:

abstract class A { 
    def aval : String 
    assert(aval != null, "aval == null") 
    assert(aval == "B", "aval: "+aval) 
} 

class B extends A { 
    def aval = "B" 
} 

class C extends A { 
    val aval = "B" 
} 

object VariousScalaTests { 
    def main(args : Array[String]) : Unit = { 
     val b = new B 
     val c = new C 
    } 
} 

स्काला त्रुटि:

Exception in thread "main" java.lang.AssertionError: assertion failed: aval == null 
    at scala.Predef$.assert(Predef.scala:92) 
    at A.<init>(VariousScalaTests.scala:4) 
    at C.<init>(VariousScalaTests.scala:12) 
    at VariousScalaTests$.main(VariousScalaTests.scala:19) 
    at VariousScalaTests.main(VariousScalaTests.scala) 

तो यह में विफल रहता है कोड की अंतिम पंक्ति: "वैल सी = नया सी"। कक्षा बी पूरी तरह से काम करता है, लेकिन कक्षा सी नहीं करता है! केवल अंतर यह है कि सी "वाल" और बी का उपयोग करके "डीफ़" का उपयोग करके aval लागू करता है।

तो मेरा सवाल, सबसे अधिक, यह अंतर क्यों? मुझे समझ में नहीं आता कि क्या हो रहा है।

और क्या यह काम करने के लिए एक तरीका है क्योंकि मैं दोनों मामलों में स्कैला में चाहता हूं? या क्या मैं सिर्फ स्काला में जो चाहता हूं उसे ज़ोर देने का एक और शानदार तरीका याद कर रहा हूं?

उत्तर

5

यह बराबर जावा कोड समस्या की व्याख्या करनी चाहिए: जब आप

val c = new C 

A रन से पहले C के निर्माता के निर्माता और _aval क्षेत्र चलाने

public abstract class A { 
    public String aval(); 
} 

public class B extends A { 
    public String aval() { 
     return "B"; 
    } 
} 

public class C extends A { 
    private String _aval; 

    public C() { 
     _aval = "B"; 
    } 

    public String aval() { 
     return _aval; 
    } 
} 

निर्दिष्ट नहीं की गई अभी तक। तो aval() विधि null (_aval फ़ील्ड का प्रारंभिक मान) लौटाता है। लेकिन

val b = new B 

ऐसी कोई समस्या नहीं है।

आम तौर पर, you should try to avoid calling virtual methods from a constructor.

And is there a way to make it work as I want in both cases in scala?

कुछ दृष्टिकोण के लिए this question देखें।

+0

आपका जावा कोड अच्छी तरह से बताते हैं! अब मैं देखता हूं ... इस तरह के व्यवहार को ध्यान में रखते हुए, "एक निर्माता से आभासी तरीकों को कॉल करने से बचें" बहुत अच्छी सलाह लगता है। निश्चित रूप से स्कैला में, जावा कोड के रूप में यह और भी स्पष्ट है कि क्या हो रहा है। मैं अपने विशिष्ट मामले में सबक्लास को सुंदर ढंग से जांचने के लिए एक और तरीका खोजूंगा, आपका लिंक मदद कर सकता है। कम से कम इस त्रुटि का रहस्य अब चला गया है ;-) –

6

स्काला में आप उपवर्ग के वैल से पहले सुपर निर्माता कहा जाता है प्रारंभ पैदा करने के लिए सुविधा जल्दी परिभाषाओं का उपयोग कर सकते हैं:

class C extends { 
    val aval = "B" 
} with A 
+0

इस सुविधा को प्रारंभिक फ़ील्ड कहा जाता है, है ना? – missingfaktor

+0

सुनिश्चित नहीं है। स्कैला लैंग स्पेक सेक्शन 5.1.6 में इसे "प्रारंभिक परिभाषा" कहा जाता है। – venechka

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