2014-12-23 11 views
6

के रूप में उपचार पैरामीटर बनाम स्विफ्ट जेनिक्स बनाम समझना क्या कोई मुझे बेस क्लास या प्रोटोकॉल का उपयोग करने पर जेनिक्स का उपयोग करने के लाभों को समझने में मदद कर सकता है? शायद मैं सिर्फ प्रोटोकॉल या बेस टाइप

func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) 
{ 
    var index = find(array, object) 
    array.removeAtIndex(index!) 
} 

क्यों नहीं बस इसे इस प्रकार लिख स्विफ्ट के लिए कुछ और समय के लिए गाइड पढ़ने की जरूरत है, लेकिन जेनरिक की अवधारणा सिर्फ में डूब नहीं है। जेनरिक

का उपयोग कर इस उदाहरण पर विचार?

// As pointed out, this does not compile. I was more-so curious as to why 
func removeObject(object: Equatable, inout fromArray array: [Equatable]) 
{ 
    var index = find(array, object) 
    array.removeAtIndex(index!) 
} 

आपकी स्पष्टीकरण के लिए धन्यवाद।


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

मेरा प्रश्न इस बारे में कुछ अंतर्दृष्टि प्राप्त करने के लिए था कि स्विफ्ट में इसी तरह के पैटर्न की अनुमति क्यों नहीं है, और इसके बजाय जेनिक्स का उपयोग क्यों किया जाता है।

+1

आपका दूसरा स्निपेट संकलित नहीं हो रहा है, यह प्रोटोकॉल फेंकता है Equatable केवल सामान्य बाधा 'कंपाइलर त्रुटि के रूप में उपयोग किया जा सकता है। खैर, संकलन करने में सक्षम होना काफी लाभ है, है ना? ;) – siejkowski

+0

मुझे लगता है कि यह एक उत्कृष्ट प्रश्न है जो गहरे मुद्दों पर पड़ता है। हां, दूसरा स्निपेट संकलित नहीं है। क्यों नहीं? संकलक इसे संकलित क्यों नहीं कर सकता? वह भाषा उस तरह क्यों काम करती है? – algal

उत्तर

5

प्रोटोकॉल के मामले में, यह प्रोटोकॉल पर ही निर्भर करता है। यदि प्रोटोकॉल Self या typealias का उपयोग करता है, तो इसका उपयोग सीधे नहीं किया जा सकता है। किसी अन्य प्रोटोकॉल के लिए, आप protocol<MyProtocol> प्रकार के चर और पैरामीटर घोषित कर सकते हैं, उदाहरण के लिए, var o: protocol<MyProtocol>

कारण आप var o: protocol<Equatable> नहीं कह सकता क्योंकि Equatable प्रोटोकॉल एक तरह से यह वाणी है कुछ शर्तों के कि (इस मामले Self में) में बनाया गया है संतुष्ट होना चाहिए, और इस प्रकार यह केवल एक सामान्य प्रकार बाधा के रूप में इस्तेमाल किया जा सकता है। दूसरे शब्दों में, संकलक संकलन समय पर SelfEquatable पर किसी भी चीज़ के संबंध में है, और यह var o: protocol<Equatable> में ऐसा नहीं कर सकता है।

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

class Useless<T> { 
    private let o: T 
    private let callback: (T, String) -> Void 
    required init(o: T, callback: (T, String) -> Void) { 
     self.o = o 
     self.callback = callback 
    } 
    func publish(message: String) { 
     callback(o, message) 
    } 
} 

var useless = Useless(o: myObject) { obj, message in 
    // Here in the callback I get type safety. 
    obj.someMethod(message) 
} 

(।। इस कोड को कभी किसी के द्वारा कभी नहीं चलाया जा रहा है यह छद्म कोड के रूप में माना जाना चाहिए)

अब, यह कई कारणों से एक बहुत मूर्ख उदाहरण है, लेकिन यह बिंदु को दर्शाता है। जेनेरिक के लिए धन्यवाद, कॉलबैक के obj पैरामीटर पूरी तरह से टाइप-सुरक्षित है। यह बेस क्लास या प्रोटोकॉल के साथ नहीं किया जा सका क्योंकि हम कभी भी उम्मीद नहीं कर सकते कि कॉलबैक में कौन सा कोड कॉल किया जा सकता है। Useless कक्षा किसी भी को T के रूप में टाइप कर सकती है।

0

आपका उदाहरण वास्तव में अच्छा नहीं है, दूसरा उदाहरण संकलित नहीं होता है क्योंकि समेकित प्रोटोकॉल में स्वयं के संदर्भ हैं और, जैसा कि पैरामीटर प्रकार के रूप में उपयोग नहीं किया जा सकता है।

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

6

मुझे लगता है कि स्विफ्ट टीम द्वारा एक देव मंच पोस्ट किया गया है कि दूसरे उदाहरण के लिए शॉर्टेंड के रूप में दूसरा उदाहरण देने में सक्षम होना कितना अच्छा होगा।हालांकि, मुझे लगता है कि यह वास्तव में एक सामान्य कार्य होगा - एक घोषित करने के लिए सिर्फ एक शॉर्टेंड?

यह अलग कैसे होगा? जैसा कि अन्य उत्तरों ने इंगित किया है, Equatable केवल सामान्य रूप से उपयोग किया जा सकता है। लेकिन चलो एक उदाहरण लें जो होना जरूरी नहीं है। कैसे यह है:

इस से
func f<T: Printable>(t: T) { 
    // do some stuff 
} 

अलग:

func g(p: Printable) { 
    // do some stuff 
} 

अंतर है, f कार्यों के एक परिवार है कि संकलन समय पर उत्पन्न कर रहे हैं परिभाषित करता है, जो कुछ के साथ क्या t के रूप में पारित हो जाता है के प्रकार T के लिए प्रतिस्थापित। * तो यदि आप Int में पास हुए हैं, तो ऐसा होगा कि आपने एक संस्करण func f(t: Int) { … } लिखा होगा। यदि आप एक Double में पारित कर दिया है, यह func f(t: Double) { … }

लेखन जैसा होगा * इस एक से अधिक सरलीकरण है, लेकिन अब के लिए इसके साथ जाना ...

दूसरी ओर, g केवल एक ही समारोह, उस पर है रनटाइम केवल Printable प्रोटोकॉल का संदर्भ स्वीकार कर सकता है।

अभ्यास में मतभेद लगभग अपरिहार्य हैं। उदाहरण के लिए, यदि आप किसी अन्य समारोह के लिए f अंदर t पारित यह इस तरह काम करता है:

func f(i: Int) { 
    // h doesn’t receive an Int 
    // but a Printable: 
    h(i as Printable) 
} 
उदाहरण के लिए

तो:

func f<T: Printable>(t: T) { 
    println(sizeof(t)) 
} 

f(1 as Int8) // prints 1 
f(1 as Int64) // prints 8 
:

func h(i: Int) { 
    println("An Int!") 
} 

func h(p: Printable) { 
    println("A Printable!") 
} 

func f<T: Printable>(t: T) { 
    h(t) 
} 

h(1) // prints "An Int!" 
f(1) // prints "A Printable!" 

आप थोड़ा तरीके में अंतर है, हालांकि देख सकते हैं

सबसे बड़ा अंतर यह है कि वे वास्तविक जेनेरिक प्रकार को प्रोटोकॉल नहीं लौटा सकते हैं:

func f<T: Printable>(t: T) -> T { 
    return t 
} 

func g(p: Printable) -> Printable { 
    return p 
} 

let a = f(1) // a is an Int 
let b = f([1]) // b is an [Int] 

let c = g(1) // c is a Printable 
let d = g([1]) // d is a Printable 

यह अंतिम उदाहरण यह समझने की कुंजी है कि संबंधित प्रकारों के प्रोटोकॉल का उपयोग केवल सामान्य रूप से क्यों किया जा सकता है। आप first का अपना स्वयं का कार्यान्वयन करना चाहता था मान लीजिए:

func first<C: CollectionType>(x: C) -> C.Generator.Element? { 
    if x.startIndex != x.endIndex { 
     return x[x.startIndex] 
    } 
    else { 
     return nil 
    } 
} 

तो first एक सामान्य समारोह, और सिर्फ एक नियमित रूप से समारोह है कि एक CollectionType प्रोटोकॉल का एक तर्क प्राप्त नहीं था, कैसे यह क्या भिन्नता है संभव हो जाएगा यह लौटा हुआ?

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