2016-06-08 12 views
7

मैं यह पता लगाने की कैसे एक समारोह जो निम्नलिखित दो पैरामीटर लेता है परिभाषित करने के लिए कोशिश कर रहा हूँ के रूप में लेता है (!):समारोह है कि एक प्रोटोकॉल और एक अनुरूप वर्ग उदाहरण पैरामीटर

  1. एक प्रोटोकॉल।
  2. वर्ग (संदर्भ प्रकार) का एक उदाहरण उस प्रोटोकॉल के अनुरूप है।

उदाहरण के लिए,

protocol P { } 
class C : P { } // Class, conforming to P 
class D { }  // Class, not conforming to P 
struct E: P { } // Struct, conforming to P 

दिया इस संकलन करना चाहिए:

register(P.self, obj: C()) // (1) 

लेकिन इन संकलन नहीं करना चाहिए:

register(P.self, obj: D()) // (2) D does not conform to P 
register(P.self, obj: E()) // (3) E is not a class 

यह है कि अगर हम हालत ड्रॉप आसान है दूसरा पैरामीटर एक वर्ग उदाहरण है:

func register<T>(proto: T.Type, obj: T) { 
    // ... 
} 

लेकिन यह (3) में संरचना (मान प्रकार) को भी स्वीकार करेगा। इस होनहार देखा और संकलित

func register<T: AnyObject>(proto: T.Type, obj: T) { 
    // ... 
} 

लेकिन फिर (1), (2), (3) में से कोई भी संकलन अब, उदा

register(P.self, obj: C()) // (1) 
// error: cannot invoke 'register' with an argument list of type '(P.Protocol, obj: C)' 

मैं कि संकलक त्रुटि के लिए कारण Protocol doesn't conform to itself? में रूप में ही है मान

एक और असफल प्रयास

func register<T>(proto: T.Type, obj: protocol<T, AnyObject>) { } 
// error: non-protocol type 'T' cannot be used within 'protocol<...>' 

एक व्यवहार्य विकल्प के एक समारोह जो पैरामीटर के रूप में

  1. एक वर्ग प्रोटोकॉल लेता होगा।
  2. उस प्रोटोकॉल के अनुरूप एक प्रकार का एक उदाहरण।

यहां समस्या यह है कि पहले पैरामीटर को प्रतिबंधित कैसे करें, केवल कक्षा प्रोटोकॉल स्वीकार किए जाते हैं।

पृष्ठभूमि: मैं हाल ही में SwiftNotificationCenter परियोजना जो एक प्रोटोकॉल उन्मुख, प्रकार सुरक्षित अधिसूचना तंत्र लागू करता है से अधिक ठोकर खाई। यह एक register विधि है जो इस तरह दिखता है:

public class NotificationCenter { 

    public static func register<T>(protocolType: T.Type, observer: T) { 
     guard let object = observer as? AnyObject else { 
      fatalError("expecting reference type but found value type: \(observer)") 
     } 

     // ... 
    } 

    // ... 
} 

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

क्या मुझे कुछ सरल/स्पष्ट याद आ रही है?

+0

आदर्श नहीं (या बिल्कुल आपका प्रश्न), लेकिन 'प्रोटोकॉल एक्स: कक्षा {}' को परिभाषित करना सुरक्षित होगा? – sschale

+0

मैंने इस व्यवहार को पहले देखा है - एक बार जब आप एक सामान्य को बाधित करते हैं, तो ऐसा लगता है कि स्विफ्ट अब इसे एक अमूर्त प्रकार लेने की अनुमति नहीं देगा। इस मामले में 'टी'' पी 'होगा, जो एक ठोस प्रकार नहीं है। मैंने प्रोटोकॉल से जुड़े प्रकारों के साथ एक समान व्यवहार भी देखा है (एक बार जब आप उन्हें बाधित करते हैं, तो वे केवल ठोस प्रकार ले सकते हैं) - असल में एक [इसके बारे में बग रिपोर्ट] है (https://bugs.swift.org/browse/SR -1581)। – Hamish

+0

@sschale: इससे मदद मिलेगी यदि आप फ़ंक्शन को केवल कक्षा प्रोटोकॉल स्वीकार करने के लिए प्रतिबंधित कर सकते हैं (जिसे मैंने प्रबंधित नहीं किया था)। –

उत्तर

0

आप जो भी कर रहे हैं वह आप नहीं कर सकते हैं। इसका संदर्भ प्रकारों से कोई लेना देना नहीं है, ऐसा इसलिए है क्योंकि किसी भी बाधा T अस्तित्व में है, इसलिए जब आप प्रोटोकॉल के मेटाटाइप P.self: P.Protocol और एक गोद लेने वाले C का संदर्भ दे रहे हैं तो कॉल साइट पर उन्हें संतुष्ट करना असंभव है। एक विशेष मामला है जब T अनजान है जो इसे पहले स्थान पर काम करने की अनुमति देता है।

तक कहीं अधिक सामान्य मामले T: P विवश और P: class की आवश्यकता होती है, क्योंकि बस के बारे में केवल बात आप एक मनमाना प्रोटोकॉल के metatype साथ कर सकते हैं एक स्ट्रिंग के लिए नाम परिवर्तित करने के लिए है। यह इस संकीर्ण मामले में उपयोगी होता है लेकिन यह है; यह भी अच्छा होगा कि हस्ताक्षर register<T>(proto: Any.Type, obj: T) हो सकता है।

सिद्धांत में स्विफ्ट मेटाटाइप, अला register<T: AnyObject, U: AnyProtocol where T.Type: U>(proto: U, obj: T) को बाध्य करने का समर्थन कर सकता है लेकिन मुझे संदेह है कि यह कई परिदृश्यों में उपयोगी होगा।

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