2016-11-09 13 views
8

तो यह स्केला को this Java question के एक काफी सीधा बंदरगाह हैस्काला में अनावश्यक सामान्य मानकों से बचना

इस प्रकार हम लक्षण है कि जेनेरिक पैरामीटर पर ध्यान का एक समूह है:

trait Ident { } 

trait Container[I <: Ident] { 
    def foo(id: I): String 
} 

trait Entity[C <: Container[I], I <: Ident] { 
    def container: C 
    def foo(id: I) = container.foo(id) 
} 

यह काम करता है, लेकिन यह एक छोटे से है clumbsy, क्योंकि हम अध्यक्ष के प्रकार और कंटेनर के प्रकार जब इकाई की एक उप-वर्ग को परिभाषित प्रदान करने के लिए है। वास्तव में सिर्फ कंटेनर के प्रकार अपने आप में पर्याप्त प्रकार की जानकारी होगी जब:

class MyIdent extends Ident { } 
class MyContainer extends Container[MyIdent] { } 
class MyEntity extends Entity[MyContainer,MyIdent] { } 
//          ^^^^^^^ shouldn't really be necessary 

एक अस्तित्व प्रकार का उपयोग करते हुए इकाई दो पैरामीटर लेने के लिए के लिए की जरूरत से बचा जाता है ... लेकिन निश्चित रूप से आप इसे का उल्लेख नहीं कर सकते बाद में।

trait Entity[C <: Container[I] forSome { type I <: Ident }] { 
    def container: C 
    def foo(id: I) = container.foo(id) 
//   ^^^ complains it has no idea what 'I' is here 
} 

इसी सदस्य प्रकार भी काम नहीं करता है का उपयोग करने के बात परिवर्तित ... हो, तो स्काला में इस समस्या का एक सुरुचिपूर्ण समाधान

trait Ident { } 

trait Container { 
    type I <: Ident 
    def foo(id: I): String 
} 

trait Entity { 
    type C <: Container 
    def container: C 
    def foo(id: C#I) = container.foo(id) 
//         ^^ type mismatch 
} 

तो किसी को पता है?

+0

मुझे नहीं लगता कि उत्तर जावा संस्करण से बहुत अलग होगा। प्रकार के पैरामीटर को खोने के बिना वास्तव में टाइप पैरामीटर को छोड़ने का कोई तरीका नहीं है जो इसके साथ आएगा। –

+0

क्या यह 'कंटेनर' को 'वैल' बनाने का विकल्प है? – sepp2k

+0

@MichaelZajac "MyEntity" दूसरी इकाई के लिए प्रदान की पैरामीटर की परिभाषा में तो बेमानी है: वहाँ बस कोई अन्य संभव प्रकार तुम वहाँ "MyIdent" के अलावा अन्य इस्तेमाल कर सकते हैं, काफी का शाब्दिक कुछ और संकलन त्रुटियों दे देंगे। बेशक, आप स्काला में है कि अतिरेक से बच सकते हैं कि क्या मैं कैसे क्या मेरा उत्तर में प्रस्तावित की तरह कुछ नेतृत्व कर सकते हैं के लिए एक और सवाल :-) –

उत्तर

4

अद्यतनthis answer दिया मुझे यकीन है कि यह एक बग या नहीं

आप SI-4377 पर पहुंच जाते हैं विचार किया जाना चाहिए कि क्या नहीं कर रहा हूँ; यदि आप स्पष्ट प्रदान type ascriptions आपको एक त्रुटि जो मेरा अनुमान है कि मिल जाएगा बस को उजागर करता है कि प्रकार के अनुमानों existentials का उपयोग करके लागू:

trait Ident { } 

trait Container { 
    type I <: Ident 
    def foo(id: I): String 
} 

trait Entity { 

    type C <: Container 
    def container: C 
    def foo(id: C#I): String = (container: C).foo(id: C#I) 
    // you will get something like: type mismatch; 
    // [error] found : Entity.this.C#I 
    // [error] required: _3.I where val _3: Entity.this.C 
    // as I said above, see https://issues.scala-lang.org/browse/SI-4377 
} 

यह कहना है कि इस (? बग) के साथ सामान्य प्रोग्रामिंग बनाता है एक ख़ामोश नहीं है सदस्यों को एक दुःस्वप्न टाइप करें। संकलित

case object Container { 

    type is[C <: Container] = C with Container { 

    type I = C#I 
    // same for all other type members, if any 
    } 

    def is[C <: Container](c: C): is[C] = c.asInstanceOf[is[C]] 
} 

अब इसका इस्तेमाल और Entity:

trait Entity { 

    type C <: Container 
    def container: C 
    def foo(id: C#I): String = Container.is(container).foo(id) 
    // compiles! 
} 

वहाँ हैक हालांकि, मूल्यों कास्टिंग एक हाथ से तैयार किए आत्म निर्देशात्मक प्रकार उर्फ ​​करने के लिए होते हैं जो है

यह खतरनाक निश्चित रूप से है, और एक सामान्य नियम के रूप में यह सुरक्षित है ही अगर C और उसके सभी प्रकार के सदस्यों पर एक गैर-सार प्रकार बाध्य कर रहे हैं जिस बिंदु का उपयोग किया जाएगा; ध्यान दें कि यह हमेशा मामला नहीं होगा, क्योंकि स्काला आपको "अपरिभाषित" प्रकार के सदस्यों को छोड़ने देता है:

case object funnyContainer extends Container { 

    // I'm forced to implement `foo`, but *not* the `C` type member 
    def foo(id: I): String = "hi scalac!" 
} 
+1

धन्यवाद, यह काम करता है।जानकर खुशी हुई कि मेरे पास सही विचार था लेकिन बस एक बग मारा :-) –

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