2016-08-17 5 views
15

मैं एक UIViewController एक विधि से MyProtocol के अनुरूप वापस आना चाहते, तो मैं विधि हस्ताक्षर का उपयोग कर रहा:जेनेरिक्स - "सामान्य पैरामीटर 'टी' निष्कर्ष निकाला नहीं जा सका

func myMethod<T where T : UIViewController, T : MyProtocol>() -> T { 

पहली बात मुझे समझ नहीं आता: अगर myMethod रिटर्न एक MyViewController जो हस्ताक्षर के बाद किया है जैसे, मैं डाली यह मजबूर करने के लिए है:

class MyViewController: UIViewController, MyProtocol 

मैं बस return MyViewController() नहीं कर सकते हैं लेकिन मैं इस तरह यह कास्ट करने के लिए की जरूरत है: return MyViewController() as! T - ऐसा क्यों है necessar y?

और दूसरी बात: मैं इस विधि का कहीं और उपयोग कैसे कर सकता हूं? मैं बस

let x = myMethod() as? UIViewController 

नहीं कह सकता, जैसा कि मैंने त्रुटि कुछ इस तरह

Generic parameter 'T' could not be inferred 

मैं कैसे प्राप्त कर सकते हैं? अगर मैं इसे MyViewController पर डालता हूं तो यह काम करता है, लेकिन मैं निश्चित रूप से इससे बचना चाहता हूं।

संपादित करें: उदाहरण

class MyViewController : UIViewController, MyProtocol { 
} 

protocol MyProtocol { 
} 

func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { 
    return MyViewController() as! T // why is the cast necessary? 
} 

ठीक है, मैं एक हिस्सा मिलता है, लेकिन क्यों T के कलाकारों के लिए आवश्यक है? MyViewControllerUIViewController का उप-वर्ग है और प्रोटोकॉल के अनुरूप है, इसलिए कोई कलाकार आवश्यक नहीं होना चाहिए, है ना?

+0

आप यहां क्या हासिल करने की कोशिश कर रहे हैं? आप जेनेरिक का उपयोग पहली जगह क्यों कर रहे हैं? – Alexander

+0

मैं एक प्रकार के साथ काम करना चाहता हूं जो 'UIViewController' है और विशिष्ट प्रोटोकॉल के अनुरूप है; मेरे पास अलग-अलग वर्ग हैं जो इस नियमों के अनुरूप हैं, इसलिए मैं एक विशिष्ट प्रकार का उपयोग नहीं करना चाहता हूं। – swalkner

+0

क्या आप उत्तर स्वीकार नहीं करना चाहते हैं? – Honey

उत्तर

17
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T 

इस घोषणा का कहना है: एक समारोह myMethod कहा जाता है, मौजूद है ऐसा है कि myMethod रिटर्न कुछ विशिष्टT जहां TUIViewController और भी MyProtocol की एक उप-प्रकार है। यह नहीं कहता कि T वास्तव में क्या है, और यह नहीं कहता कि केवल myMethod है। अगर कई प्रकार हैं जो UIViewController के उप-वर्ग हैं और MyProtocol के अनुरूप हैं तो कई लोग हो सकते हैं। उन सभी प्रकारों में से प्रत्येक myMethod का नया संस्करण बनाता है (वास्तव में myMethod के लिए एक नया समाधान बनाता है, ऐसा कोई कार्य मौजूद है)। कहते हैं कि

func myMethod() -> UIViewController 

:

यह रूप में एक ही बात नहीं है समारोह myMethodUIViewController के किसी भी उप-प्रकार देता है।

स्विफ्ट में कोई भी तरीका नहीं है "किसी भी प्रकार जो UIViewController का उप-वर्ग है और MyProtocol का उप-प्रकार है।" आप केवल उस विशिष्ट प्रकार पर चर्चा कर सकते हैं जो उस मानदंड को पूरा करता है। स्विफ्ट इस तरह कक्षाओं और प्रोटोकॉल को गठबंधन नहीं कर सकता; यह सिर्फ भाषा की वर्तमान सीमा है, न कि एक गहरी डिजाइन समस्या।

विशिष्ट बनाम कोई समस्या है। ऐसे कई कार्य हैं जो आपके myMethod घोषणा को संतुष्ट करते हैं। प्रत्येक T आप प्लग इन कर सकते हैं नियमों के अनुरूप एक उम्मीदवार होगा। तो जब आप myMethod() कहते हैं, तो संकलक नहीं जानता कि कौन सा विशिष्ट T आपका मतलब है।

(मैं कम प्रकार- सिद्धांत रूप में यह प्रदान करने के लिए इस उत्तर का विस्तार करने के लिए जा रहा था, और अधिक शब्द "आप इसे कैसे कोड में क्या करते", लेकिन donnywals पहले से ही उस का एक बहुत अच्छा संस्करण है।)

* आपकी संपादित सवाल करने के लिए *

func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { 
    return MyViewController() as! T // why is the cast necessary? 
} 

T एक विशिष्ट फोन करने वाले ने निर्णय लिया प्रकार है। यह "किसी भी प्रकार का अनुरूप नहीं है" यह "कुछ विशिष्ट, ठोस प्रकार है जो अनुरूप है।" ऐसा होता है कि आप कहा जाता है पर विचार करें:

let vc: SomeOtherViewController = myMethod() 

इस मामले में, TSomeOtherViewController है। MyViewController उस प्रकार का नहीं है, तो आप as! कलाकार के साथ क्या कर रहे हैं वह खतरनाक है।

8

इस तरह की एक विधि में, T लौटने का अर्थ है कि आपको T वापस करना होगा। यदि आप MyViewController वापस करते हैं, तो वापसी का प्रकार MyViewController होना चाहिए। T एक सामान्य प्रकार है जो स्विफ्ट कंपाइलर जो कुछ भी अनुमान लगा सकता है उसका रूप लेगा।

तो, आपके विधि हस्ताक्षर के साथ, प्रोटोकॉल और विधि का एक सरल कार्यान्वयन इस तरह दिख सकता है।

protocol MyProtocol { 
    var name: String { get set } 
} 

func myMethod<T where T : UIViewController, T : MyProtocol>() -> T { 
    var vc = T() 
    vc.name = "Hello, world" 
    return vc 
} 

तो, अपने उपयोग उदाहरण पर विचार:

let x = myMethod() 

कैसे संकलक पता होगा क्या T की ठोस प्रकार है? MyViewController का संकेत देने के लिए कुछ भी नहीं है। केवल एक चीज जो हम जानते हैं वह है कि जो भी T है, यह MyViewController या इसके उप-वर्ग होना चाहिए। और यह MyProtocol के अनुरूप होना चाहिए। लेकिन यह T के प्रकार के बारे में जानकारी प्रदान नहीं करता है।

एकमात्र ऐसा स्थान जहां संकलक अनुमान लगा सकता है कि हम T वापसी मूल्य के माध्यम से चाहते हैं। <> के बीच सभी कोड T के लिए बाध्य हैं। -> T एकमात्र ऐसा स्थान है जहां T बाधाओं के बाहर देखा जाता है। तो अगर हम किसी भी तरह संकलक को बता सकते हैं कि हम myMethod वापस लौटने के लिए चाहते हैं, तो हमने T अनुमान लगाने के लिए पर्याप्त जानकारी दी है।

आपका टाइपकास्ट काम करता है लेकिन मैं मानता हूं कि यह बहुत सुंदर नहीं है। T अनुमान लगाने के लिए कंपाइलर के लिए एक बहुत ही सुंदर तरीका यह है।

let vc: MyViewController = myMethod() 

vc के प्रकार निर्दिष्ट करके, संकलक समझता है कि हम myMethod एक MyViewController वापस जाने के लिए चाहते हैं। तो अब T के प्रकार का अनुमान लगाया जा सकता है और यदि हम T लौटते हैं, तो हम वास्तव में MyViewController लौटाते हैं।

+0

बहुत बहुत धन्यवाद; सिर्फ एक और सवाल, कृपया मेरा संपादन – swalkner

+0

@donnywals सामान्य विधि पैरामीटर के बारे में कैसे, वापसी प्रकार नहीं देखें? आप इस तरह कुछ कैसे अनुमान लगाते हैं? – Axel

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