2015-01-13 10 views
27

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

class Translator<T:Hashable> {...} 

class FooTranslator<String>:Translator<String> {...} 

विचार यह है कि अनुवादक टी को एक शब्दकोश में कुंजी के प्रकार के रूप में उपयोग करता है। यह उदाहरण हो सकता है एक स्ट्रिंग या एक enum। Subclass कंक्रीट शब्दकोश प्रदान करता है।

लेकिन यह इस वजह से विफल रहता है:

"प्रकार 'स्ट्रिंग' 'Hashable' प्रोटोकॉल के अनुरूप नहीं है" लेकिन स्ट्रिंग Hashable के अनुरूप है! क्या मैं पागल हूँ यह इंट के साथ भी काम नहीं करता है, जो हैशबल के अनुरूप भी है। यह काम नहीं करता है अगर मैं इक्टेबल के साथ हैशबल को प्रतिस्थापित करता हूं, जिसे दोनों द्वारा भी कार्यान्वित किया जाना चाहिए।

अगर मैं सिर्फ परीक्षण के लिए प्रकार बाधा को हटाने, (जहां मैं भी शब्दकोश निष्क्रिय करने के लिए है, के रूप में मैं कुछ भी वहाँ कुंजी के रूप में hashable नहीं उपयोग नहीं कर सकते) - यह संकलित

class Translator<T> {...} 

class FooTranslator<String>:Translator<String> {...} 

मैं क्या कर रहा हूँ गलत कर रहे हो

उत्तर

17

मैं एक स्विफ्ट डेवलपर नहीं कर रहा हूँ, लेकिन जावा में इसी तरह की समस्याओं देखा है, मुझे लगता है समस्या यह है कि इस समय आप एक प्रकार पैरामीटर क्योंकि आप class FooTranslator<String> घोषणा कर रहे String बुलाया घोषणा कर रहे है - तो प्रकार तर्कTranslator<String> में बस उस प्रकार का पैरामीटर है, जिसमें कोई बाधा नहीं है। आप नहीं है चाहिए, तो एक प्रकार पैरामीटर, मुझे लगता है (है अर्थात आप नहीं चाहते अपने FooTranslator एक सामान्य वर्ग में ही। होने के लिए)

टिप्पणी में बताया गया है स्विफ्ट subclasses of a generic class also have to be generic में,। आप संभवतः एक थ्रो-दूर प्रकार पैरामीटर की घोषणा कर सकता है, इस तरह:

class FooTranslator<T>:Translator<String> 

जो अभी भी एक नए प्रकार के पैरामीटर String कहा जाता है, जो कि समस्या क्या पैदा कर रहा था था की घोषणा टाल। इसका मतलब है कि जब आप किसी भी प्रकार के पैरामीटर नहीं चाहते हैं, तो यह एक नया प्रकार पैरामीटर पेश कर रहा है, लेकिन यह संभवतः कुछ भी नहीं है ...

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

typealias FooTranslator = Translator<String> 

या यहां तक ​​कि एक भयानक तरह से मिश्रण दो, यदि आप वास्तव में चाहते हैं: दूसरी ओर, अगर आप सिर्फ एक प्रकार है जो Translator<String> रूप बिल्कुल ही है चाहता हूँ, आप के बजाय एक प्रकार अन्य नाम का उपयोग करना चाहिए एक उपवर्ग लेकिन करने के लिए एक सामान्य तरीके से यह उल्लेख करने के लिए है नहीं करना चाहती:

class GenericFooTranslator<T>:Translator<String> 
typealias FooTranslator = GenericFooTranslator<Int> 

(ध्यान दें कि यहां Int जानबूझ कर नहीं String, पता चलता है कि Translator में T के समान नहीं है Tमें)

+0

ऐसा नहीं है। इसके बारे में एक स्विफ्ट मुद्दा/सीमा है, http://stackoverflow.com/questions/24138359/limitation-with-classes-derived-from-generic-classes-in-swift – Ixx

+0

@lxx: Ick देखें। मुझे संदेह है कि अभी भी * कारण * है, लेकिन आप एक अलग समाधान चाहते हैं। मैंने कोशिश करने के लिए एक संभावित समाधान के साथ अपना जवाब संपादित किया है। –

+0

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

96

शुरुआत के लिए, की त्रुटि स्पष्ट करता हूं:

को देखते हुए:

class Foo<T:Hashable> { } 

class SubFoo<String> : Foo<String> { } 

यहाँ भ्रामक बात यह है कि हम उम्मीद करते हैं "स्ट्रिंग" स्विफ्ट परिभाषित संरचना जो पात्रों का एक संग्रह रखती है मतलब है। लेकिन ऐसा नहीं है।

यहां, "स्ट्रिंग" सामान्य प्रकार का नाम है जिसे हमने अपना नया सबक्लास, SubFoo दिया है।

class SubFoo<String> : Foo<T> { } 

यह पंक्ति एक अघोषित प्रकार के उपयोग के रूप T के लिए एक त्रुटि उत्पन्न करता है: यदि हम कुछ बदलाव करने यह बहुत स्पष्ट हो जाता है।

तो अगर हम इस के लिए लाइन बदलने के लिए:

class SubFoo<T> : Foo<T> { } 

हम वापस वही त्रुटि आप मूल रूप से किया था करने के लिए कर रहे हैं, 'टी' 'Hashable' के अनुरूप नहीं है। यह यहां स्पष्ट है, क्योंकि टी भ्रमित रूप से मौजूदा स्विफ्ट प्रकार का नाम नहीं है जो 'हैशबल' के अनुरूप होता है। यह स्पष्ट है 'टी' एक सामान्य है।

जब हम 'स्ट्रिंग' लिखते हैं, तो यह सामान्य प्रकार के प्लेसहोल्डर नाम भी है, और वास्तव में String प्रकार स्विफ्ट में मौजूद नहीं है।


हम एक सामान्य वर्ग की एक विशिष्ट प्रकार के लिए एक अलग नाम चाहते हैं, उचित दृष्टिकोण लगभग निश्चित रूप से एक typealias है:

class Foo<T:Hashable> { 

} 

typealias StringFoo = Foo<String> 

यह पूरी तरह से वैध है स्विफ्ट, और यह सिर्फ ठीक संकलित करता है।


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

मूल समस्या के लिए वापस जा रहे हैं, की पहली त्रुटि से छुटकारा पाने करते हैं:

class Foo<T: Hashable> 

class SubFoo<T: Hashable> : Foo<T> { } 

यह पूरी तरह से वैध स्विफ्ट है। लेकिन यह हम जो कर रहे हैं उसके लिए यह विशेष रूप से उपयोगी नहीं हो सकता है।

केवल कारण है कि हम निम्न कार्य नहीं कर सकते हैं: क्योंकि String एक स्विफ्ट वर्ग नहीं है

class SubFoo<T: String> : Foo<T> { } 

बस है - यह एक संरचना है। और किसी भी संरचना के लिए इसकी अनुमति नहीं है।


हम एक नए प्रोटोकॉल कि Hashable से विरासत लिखते हैं, हम उस का उपयोग कर सकते हैं:

protocol MyProtocol : Hashable { } 

class Foo<T: Hashable> { } 
class SubFoo<T: MyProtocol> : Foo<T> { } 

यह पूरी तरह से वैध है।

ही, ध्यान दें कि हम वास्तव में Hashable से विरासत की जरूरत नहीं है कि:

protocol MyProtocol { } 
class Foo<T: Hashable> { } 
class SubFoo<T: Hashable, MyProtocol> { } 

यह भी पूरी तरह से वैध है।

हालांकि, ध्यान दें कि, किसी भी कारण से, स्विफ्ट आपको यहां कक्षा का उपयोग करने नहीं देगा। उदाहरण के लिए:

class MyClass : Hashable { } 

class Foo<T: Hashable> { } 
class SubFoo<T: MyClass> : Foo<T> { } 

स्विफ्ट रहस्यमय तरीके से शिकायत है कि 'टी' 'Hashable' (यहां तक ​​कि जब हम आवश्यक कोड जोड़ने यह इतना बनाने के लिए के अनुरूप नहीं है


अंत में, सही। दृष्टिकोण, और सबसे स्विफ्ट-उपयुक्त दृष्टिकोण 'हैशबल' से प्राप्त एक नया प्रोटोकॉल लिखने जा रहा है और आपको जो भी कार्यक्षमता चाहिए उसे जोड़ता है।

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

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