2012-03-08 27 views
31

मैं एक विशेषता के अंदर एक covariant प्रकार पैरामीटर का उपयोग करें ताकि तरह के मामले स्तरीय निर्माण करने के लिए कोशिश कर रहा हूँ:contravariant स्थिति में पैरामीटर क्यों है?

trait MyTrait[+T] { 
    private case class MyClass(c: T) 
} 

संकलक का कहना है:

error: covariant type T occurs in contravariant position in type T of value c 

मैं तो कोशिश की निम्नलिखित लेकिन यह भी नहीं था 'टी काम:

trait MyTrait[+T] { 
    private case class MyClass[U <: T](c: U) 
} 

त्रुटि इस समय है:

error: covariant type T occurs in contravariant position in type >: Nothing <: T of type U 

क्या कोई यह समझा सकता है कि टी यहां एक सहकारी स्थिति क्यों है और इस समस्या का समाधान सुझाता है? Thx!

+0

क्या आप समझा सकते हैं कि आप वास्तव में क्या करना चाहते हैं? आप टी covariant क्यों नहीं चाहते हैं और invariant नहीं? –

उत्तर

61

यह ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के रूप में यह हकदार है कि के रूप में ज्यादा ध्यान नहीं मिलता है की एक बुनियादी सुविधा है।

मान लीजिए आप एक संग्रह C[+T] है। +T का अर्थ यह है कि यदि U <: T, तो C[U] <: C[T]। काफी उचित। लेकिन उप-वर्ग होने का क्या अर्थ है? इसका मतलब है कि प्रत्येक विधि को काम करना चाहिए जो मूल वर्ग पर काम करता है। तो, मान लीजिए कि आपके पास m(t: T) विधि है। यह कहता है कि आप t ले सकते हैं और इसके साथ कुछ कर सकते हैं। लेकिन C[U] केवल U के साथ काम कर सकता है, जो T के सभी नहीं हो सकता है! तो आपने तुरंत अपने दावे का खंडन किया है कि C[U]C[T] का उप-वर्ग है। यह नहीं है। ऐसी चीजें हैं जो आप C[T] के साथ कर सकते हैं कि आप C[U] के साथ नहीं कर सकते हैं।

अब, आप इसके आसपास कैसे जाते हैं?

एक विकल्प वर्ग अपरिवर्तनीय (ड्रॉप +) बनाना है। एक अन्य विकल्प यह है कि यदि आप किसी भी superclass को भी अनुमति देने के लिए विधि पैरामीटर लेते हैं, तो m[S >: T](s: S)। अब अगर U करने के लिए T परिवर्तन, यह कोई बड़ी बात नहीं है: T की एक सुपर क्लास भी U की एक सुपर क्लास है, और विधि काम करेंगे। (हालांकि, आप तो अपने विधि ऐसी बातों को संभालने के लिए सक्षम होने के लिए बदलना होगा।)

एक मामले वर्ग के साथ

, यह सही है जब तक आप यह अपरिवर्तनीय कर इसे पाने के लिए और भी कठिन है। मैं ऐसा करने की सलाह देता हूं, और जेनेरिक और भिन्नता को कहीं और दबा रहा हूं। लेकिन मुझे यह सुनिश्चित करने के लिए और अधिक विवरण देखना होगा कि यह आपके उपयोग के मामले के लिए काम करेगा।

+0

आपके उत्तर के लिए धन्यवाद। हालांकि आपका समाधान मेरे लिए इस मामले में काम नहीं करता है। कॉन्वर्सिस को छोड़ना और विशेषता का आविष्कार करना काम करेगा लेकिन यह वही नहीं है जो मैं चाहता हूं। एक सुपरटेप लेने के लिए विधि (या मेरे मामले में केस-क्लास) को अनुमति देना भी संतोषजनक नहीं है। मुझे उत्सुकता है कि मामले-वर्गों के लिए चीजें सही क्यों होती हैं। ध्यान दें कि _case_ कीवर्ड के बिना एक ही कोड ठीक काम करता है। – lapislazuli

+2

@lapislazuli - क्योंकि केस कक्षाओं में एक साथी विधि शामिल होती है जो उन्हें बनाता है ('टी' को तर्क के रूप में लेना), इसलिए आपको ऊपर दिए गए विधि प्रतिबंधों का पालन करना होगा। यदि आप 'केस' शामिल नहीं करते हैं, तो कक्षा इंटरफ़ेस में एक विधि का अर्थ नहीं देती है जो 'टी 'लेती है। –

+0

धन्यवाद रेक्स, अब यह मुझे समझ में आता है! – lapislazuli

13

लगभग वहां। यहाँ:

scala> trait MyTrait[+T] { 
    | private case class MyClass[U >: T](c: U) 
    | } 
defined trait MyTrait 

जिसका मतलब है MyClass[Any] सभी T लिए मान्य है। यह उस स्थिति में है कि कोई उस स्थिति में T का उपयोग क्यों नहीं कर सकता है, लेकिन यह दर्शाता है कि इस समय मुझे मूड में रहने की तुलना में अधिक कोड की आवश्यकता है। :-)