2009-12-02 7 views
27

नीचे दी गई त्रुटि क्यों है? इसे कैसे कामयाब करें?एक वर्ग एक ही हस्ताक्षर की विधि के साथ लक्षण क्यों बढ़ा सकता है?

संपादित करें: मुझे लगता है कि चूंकि ए और बी संकलन (इंटरफेस, कक्षा) जोड़े के लिए संकलित करते हैं, इसलिए सी संकलन करते समय लागू करने के लिए सही स्थैतिक विधि कॉल चुनना एक मामला है। मैं प्राथमिकता को आदेश के अनुसार होने की अपेक्षा करता हूं।

 
scala> trait A {def hi = println("A")} 
defined trait A 

scala> trait B {def hi = println("B")} 
defined trait B 

scala> class C extends B with A 
:6: error: error overriding method hi in trait B of type => Unit; 
method hi in trait A of type => Unit needs `override' modifier 
     class C extends B with A 

scala> trait A {override def hi = println("A")} 
:4: error: method hi overrides nothing 
     trait A {override def hi = println("A")} 

संपादित करें: ध्यान दें कि रूबी में यह अच्छी तरह से काम करता है:

 
>> module B; def hi; puts 'B'; end; end 
=> nil 
>> module A; def hi; puts 'A'; end; end 
=> nil 
>> class C; include A; include B; end 
=> C 
>> c = C.new 
=> # 
>> c.hi 
B 
=> nil 

उत्तर

51

यह 2.8 और 2.11 में मेरे लिए काम करता है, और आप लक्षण A या B में गैर हस्तक्षेप करने वाला करने की अनुमति होगी:

trait A { def hi = println("A") } 
trait B { def hi = println("B") } 

class C extends A with B { 
    override def hi = super[B].hi 
    def howdy = super[A].hi // if you still want A#hi available 
} 

object App extends Application { 
    (new C).hi // prints "B" 
} 
+3

उत्कृष्ट! बहुत बुरा है कि अगर मैं 'कक्षा सी ए के साथ बी बढ़ाता है' की कोशिश करता हूं, तो त्रुटि संघर्ष को हल करने के इस तरीके का उल्लेख नहीं करती है। – IttayD

+0

@ स्काला 2.10.4 के साथ IttayD: त्रुटि संदेश कहता है कि इसे कैसे हल करें: (नोट: इसे कक्षा सी में ओवरराइड घोषित करके हल किया जा सकता है) कक्षा सी ए के साथ बी बढ़ाता है { –

12

आप एक आम आधार विशेषता इस्तेमाल कर सकते हैं, Base कहते हैं, इस प्रकार है:

trait Base {def hi: Unit} 
trait A extends Base {override def hi = println("A")} 
trait B extends Base {override def hi = println("B")} 
class C extends A with B 
प्रकार पदानुक्रम के साथ

hi को कॉल करने का नतीजा निम्नानुसार है (लक्षणों को तुरंत चालू करने के लिए {} का उपयोग नोट करें):

scala> (new A {}).hi 
A 

scala> (new B {}).hi 
B 

scala> (new C).hi 
B 
+0

धन्यवाद। मैं एक घुसपैठ समाधान के लिए उम्मीद कर रहा था। कुछ ऐसा जो अकेले सी में किया जा सकता है (जैसे कि ए और बी विभिन्न तृतीय पक्ष पुस्तकालयों से हैं) – IttayD

1

यह diamond problem है। कौन सी विधि hi विरासत में प्राप्त की जानी चाहिए, ए से एक, या बी से एक? आम आधार विशेषता का उपयोग करके, डॉन के सुझाव के रूप में आप इसे प्राप्त कर सकते हैं।

+0

मेरा रूबी उदाहरण देखें, जहां सबकुछ ठीक है। यह 'सुपर' के अर्थशास्त्र का निर्णय लेने का मामला है। मैं सुझाव दे सकता हूं कि विस्तारित लक्षणों के पेड़ में, पहला डीएफएस बुद्धिमान चुना गया है। नोट भी यहां कोई हीरा नहीं है। बस ए, बी, सी। इसके विपरीत, समाधान बेस विशेषता बनाने के लिए है, इस प्रकार हीरा बना रहा है।तो एक हीरा एक समाधान है, यहां कोई समस्या नहीं है – IttayD

+4

[वर्ग रैखिकरण] के कारण स्कैला में कोई हीरा समस्या नहीं है (http://jim-mcbeath.blogspot.com/2009/08/scala-class-linearization.html) ... – paradigmatic

4

एक विशेषता उस वर्ग में विधियों को जोड़ती है जो इसे मिश्रित करती है। यदि दो लक्षण समान विधि जोड़ते हैं, तो वर्ग दो समान तरीकों से समाप्त होगा, जो निश्चित रूप से नहीं हो सकता है।

यदि विधि विशेषता में निजी है, हालांकि, इससे समस्या नहीं होगी। और यदि आप एक-दूसरे पर ढेर करने के तरीकों को चाहते हैं, तो आप विरासत लक्षणों पर आधार विशेषता को परिभाषित कर सकते हैं और फिर abstract override परिभाषित कर सकते हैं। हालांकि, विधि को परिभाषित करने के लिए कक्षा की आवश्यकता होती है।

scala> trait Hi { def hi: Unit } 
defined trait Hi 

scala> trait A extends Hi { abstract override def hi = { println("A"); super.hi } } 
defined trait A 

scala> trait B extends Hi { abstract override def hi = { println("B"); super.hi } } 
defined trait B 

scala> class NoHi extends Hi { def hi =() } 
defined class NoHi 

scala> class C extends NoHi with B with A 
defined class C 

scala> new C().hi 
A 
B 

अगर, हालांकि, आप वास्तव में प्रत्येक विशेषता से दो अलग-अलग तरीकों चाहते हैं, तो आप करने की आवश्यकता होगी रचनाइनहेरिट के बजाय: यहाँ इस का एक उदाहरण है।

+0

क्यों संकलक एक कार्यान्वयन के रूप में एक विधि का चयन नहीं है? चूंकि ए और बी को स्थिर तरीकों के साथ इंटरफ़ेस ए और क्लास ए $ क्लास में संकलित किया गया है, फिर JVM में यह ए और बी दोनों को लागू करने के लिए सी के लिए बिल्कुल सही है और सी में विधि हाय का अपूर्णता केवल एक $ कक्षा को कॉल कर सकता है .hi – IttayD

+0

ध्यान दें कि आपके उत्तर में, सी दो (यहां तक ​​कि तीन) समान तरीकों से समाप्त होता है, इसलिए यह काम किया जा सकता है। – IttayD

+1

यदि कोई विरासत के लिए वैचारिक आधार को फेंकने को तैयार था, तो, यह किया जा सकता है - और बाद में खेद हो सकता है। यदि आप संरचना चाहते हैं, लिखो, वारिस नहीं है। –

0

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

class somethingToTest { 
    object AImpl extends ATrait 
    object BImpl extends BTrait 

    val a = AImpl.methodDuplicated() 
    val b = BImpl.methodDuplicated() 
} 

यह शायद लक्षण उपयोग करने के लिए सबसे चतुर तरीका नहीं है, लेकिन यह परियोजना के कोड में कोई बदलाव की आवश्यकता नहीं है, यह केवल थोड़ा अधिक है करने के लिए निकलता है परीक्षण में कोड।

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