2017-02-09 14 views
8

मुझे नहीं लगता कि यह किया जा सकता है लेकिन मैं वैसे भी पूछूंगा।एक प्रोटोकॉल पर स्विफ्ट समेकनीय

protocol X {} 

और एक वर्ग:: मैं एक प्रोटोकॉल है

class Y:X {} 

मेरी कोड के बाकी में मैं प्रोटोकॉल एक्स का उपयोग कर कि कोड में सब कुछ का उल्लेख मैं कुछ करने के लिए सक्षम होने के लिए चाहते हैं जैसे:

let a:X = ... 
let b:X = ... 
if a == b {...} 

समस्या यह है कि अगर मैं लागू करने के लिए कोशिश Equatable:

protocol X: Equatable {} 
func ==(lhs:X, hrs:X) -> Bool { 
    if let l = lhs as? Y, let r = hrs as? Y { 
     return l.something == r.something 
    } 
    return false 
} 

प्रोटोकॉल के पीछे कार्यान्वयन छुपाते हुए == के उपयोग को आजमाने और अनुमति देने का विचार।

स्विफ्ट इसे पसंद नहीं करता है क्योंकि Equatable में Self संदर्भ हैं और यह अब मुझे इसे एक प्रकार के रूप में उपयोग करने की अनुमति नहीं देगा। केवल एक सामान्य तर्क के रूप में।

तो क्या किसी को प्रोटोकॉल पर एक ऑपरेटर को लागू करने का कोई तरीका नहीं मिला है, बिना किसी प्रोटोकॉल को एक प्रकार के रूप में अनुपयोगी बनने के बिना?

उत्तर

1

आपको प्रोटोकॉल एक्सटेंशनको अपने कक्षा प्रकार में को बाध्य करना होगा। उस एक्सटेंशन के अंदर आपको Equatable ऑपरेटर को लागू करना चाहिए।

public protocol Protocolable: class, Equatable 
{ 
    // Other stuff here... 
} 

public extension Protocolable where Self: TheClass 
{ 
    public static func ==(lhs: Self, rhs:Self) -> Bool 
    { 
     return lhs.name == rhs.name 
    } 
} 


public class TheClass: Protocolable 
{ 
    public var name: String 

    public init(named name: String) 
    { 
     self.name = name 
    } 
} 

let aClass: TheClass = TheClass(named: "Cars") 
let otherClass: TheClass = TheClass(named: "Wall-E") 

if aClass == otherClass 
{ 
    print("Equals") 
} 
else 
{ 
    print("Non Equals") 
} 

लेकिन मुझे सलाह है कि आप अपनी कक्षा में ऑपरेटर कार्यान्वयन जोड़ें। रखें यह सरल ;-)

+0

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

3

शायद यह उपयोगी आप के लिए किया जाएगा:

protocol X:Equatable { 
    var name: String {get set} 

} 

extension X { 
    static func ==(lhs: Self, rhs: Self) -> Bool { 
     return lhs.name == rhs.name 
    } 
} 

struct Test : X { 
    var name: String 
} 

let first = Test(name: "Test1") 
let second = Test(name: "Test2") 

print(first == second) // false 
+3

धन्यवाद, लेकिन यह तब तक काम करता है जब तक आप 'पहले = टेस्ट (नाम: "टेस्ट 1") को एक्स के रूप में कुछ करने की कोशिश नहीं करते हैं, तो आपको' एक्स 'को एक प्रकार के रूप में अनुमति नहीं देने के बारे में त्रुटि मिलती है। समस्या यह है कि मेरी कक्षाएं एपीआई के भीतर गहरी हैं और केवल प्रोटोकॉल के माध्यम से खुद को उजागर करती हैं। इसलिए उन उदाहरणों का उपयोग प्रोटोकॉल प्रकार का होना चाहिए। – drekka

3

कारण है कि आप Equatable के अनुरूप एक प्रोटोकॉल होने के बारे में दो बार सोचना चाहिए कि कई मामलों में यह सिर्फ नहीं है है समझ। इस उदाहरण पर विचार:

protocol Pet: Equatable { 
    var age: Int { get } 
} 

extension Pet { 
    static func == (lhs: Pet, rhs: Pet) -> Bool { 
    return lhs.age == rhs.age 
    } 
} 

struct Dog: Pet { 
    let age: Int 
    let favoriteFood: String 
} 

struct Cat: Pet { 
    let age: Int 
    let favoriteLitter: String 
} 

let rover: Pet = Dog(age: "1", favoriteFood: "Pizza") 
let simba: Pet = Cat(age: "1", favoriteLitter: "Purina") 

if rover == simba { 
    print("Should this be true??") 
} 

आप == के कार्यान्वयन के भीतर जाँच टाइप करने के लिए संकेत लेकिन समस्या यह है कि आप से परे उन्हें जा रहा है Pet रों प्रकार के दोनों के बारे में कोई जानकारी नहीं है कि है और आप सभी चीजें नहीं पता है कि Pet हो सकता है (हो सकता है कि आप बाद में Bird और Rabbit जोड़ दें)। यदि आप वास्तव में चाहते हैं तो आप Equatable को लागू करने के बिना == को लागू कर सकता है

protocol IsEqual { 
    func isEqualTo(_ object: Any) -> Bool 
} 

protocol Pet: IsEqual { 
    var age: Int { get } 
} 

struct Dog: Pet { 
    let age: Int 
    let favoriteFood: String 

    func isEqualTo(_ object: Any) -> Bool { 
    guard let otherDog = object as? Dog else { return false } 

    return age == otherDog.age && favoriteFood == otherDog.favoriteFood 
    } 
} 

struct Cat: Pet { 
    let age: Int 
    let favoriteLitter: String 

    func isEqualTo(_ object: Any) -> Bool { 
    guard let otherCat = object as? Cat else { return false } 

    return age == otherCat.age && favoriteLitter == otherCat.favoriteLitter 
    } 
} 

let rover: Pet = Dog(age: "1", favoriteFood: "Pizza") 
let simba: Pet = Cat(age: "1", favoriteLitter: "Purina") 

if !rover.isEqualTo(simba) { 
    print("That's more like it.") 
} 

जो बिंदु पर: आप वास्तव में इस की जरूरत है, एक और दृष्टिकोण मॉडलिंग कैसे सी # जैसी भाषाओं समानता लागू, की तरह कुछ करने से हो सकता है

static func == (lhs: IsEqual, rhs: IsEqual) -> Bool { return lhs.isEqualTo(rhs) } 

हालांकि इस मामले में आपको एक चीज देखना होगा, हालांकि विरासत है। क्योंकि आप विरासत प्रकार को कम कर सकते हैं और उस जानकारी को मिटा सकते हैं जो isEqualTo को तार्किक समझ नहीं दे सकता है।

हालांकि जाने का सबसे अच्छा तरीका केवल वर्ग/संरचना पर समानता लागू करना है और टाइपिंग जांच के लिए एक और तंत्र का उपयोग करना है।

+0

धन्यवाद। मैं 'isEqual' विकल्प (जावा से) पर विचार कर रहा हूं लेकिन था इसे आसान रखने की उम्मीद है क्योंकि मेरे पास ऐसा मामला है जहां मेरे पास अलग-अलग वर्ग हैं जो समान संदर्भपरक वस्तु का प्रतिनिधित्व करते हैं और इसलिए मैं उन्हें अलग-अलग कार्यान्वयन के बावजूद बराबर माना जाता हूं। – drekka

+0

दो अलग-अलग पर समानता लागू करना वस्तुओं के प्रकार पर एक फिसलन ढलान है। मैं उनकी तुलना करने के लिए एक और विकल्प की सिफारिश करता हूं, शायद एक प्रकार को दूसरे में बदलकर और फिर उनकी तुलना करके। –

2

Equatable के अनुरूप होने के लिए आपको अपने प्रोटोकॉल के सभी उदाहरणों की आवश्यकता क्यों नहीं है, लेकिन मैं वर्गों को उनकी समानता विधियों को लागू करना पसंद करता हूं।

// Equivalent: func doSomething<T>(element1: T, element2: T) where T: MyProtocol & Equatable { 
func doSomething<T: MyProtocol & Equatable>(element1: T, element2: T) { 
    if element1 == element2 { 
     element1.doSomething() 
    } 
} 
:

protocol MyProtocol { 
    func doSomething() 
} 

आप की आवश्यकता है कि एक वस्तु है कि MyProtocol के अनुरूप भी है Equatable आप प्रकार बाधा के रूप में MyProtocol & Equatable उपयोग कर सकते हैं:

इस मामले में, मैं प्रोटोकॉल सरल छोड़ चाहते हैं


इस तरह आप अपना विनिर्देश स्पष्ट कर सकते हैं और उप-वर्गों को केवल तभी आवश्यक होने पर अपनी समानता विधि लागू कर सकते हैं।

2

मैं अब भी पॉलिमॉर्फिज्म का उपयोग करके == को लागू करने के खिलाफ सलाह दूंगा। यह एक कोड गंध का थोड़ा सा है। यदि आप फ्रेमवर्क उपयोगकर्ता को कुछ देना चाहते हैं तो वह समानता का परीक्षण कर सकता है, तो आपको वास्तव में struct का भुगतान करना चाहिए, नहीं। यही कारण है कि कहने के लिए नहीं कर रहा है कि यह कि struct रों हालांकि वेंडिंग कर रहे हैं नहीं किया जा सकता:

struct Info: Equatable { 
    let a: Int 
    let b: String 

    static func == (lhs: Info, rhs: Info) -> Bool { 
    return lhs.a == rhs.a && lhs.b == rhs.b 
    } 
} 

protocol HasInfo { 
    var info: Info { get } 
} 

class FirstClass: HasInfo { 
    /* ... */ 
} 

class SecondClass: HasInfo { 
    /* ... */ 
} 

let x: HasInfo = FirstClass(/* ... */) 
let y: HasInfo = SecondClass(/* ... */) 

print(x == y) // nope 
print(x.info == y.info) // yep 

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

3

यदि आप सीधे प्रोटोकॉल पर Equatable लागू करते हैं, तो यह अब एक प्रकार के रूप में प्रयोग योग्य नहीं होगा, जो प्रोटोकॉल का उपयोग करने के उद्देश्य को हरा देता है। भले ही आप == प्रोटोकॉल पर Equatable अनुरूपता के बिना कार्यान्वित करते हैं, परिणाम गलत हो सकते हैं।

https://khawerkhaliq.com/blog/swift-protocols-equatable-part-one/

दृष्टिकोण है कि मैं प्रकार विलोपन उपयोग करने के लिए है सबसे अच्छा काम करने के लिए मिल गया है: इन मुद्दों में से एक प्रदर्शन के लिए अपने ब्लॉग पर यह पोस्ट देखें। यह == प्रोटोकॉल प्रकारों (प्रकार erasers में लिपटे) के लिए तुलना करने की अनुमति देता है। यह ध्यान रखना महत्वपूर्ण है कि जब हम प्रोटोकॉल स्तर पर काम करना जारी रखते हैं, तो वास्तविक == तुलना सही परिणामों को सुनिश्चित करने के लिए अंतर्निहित ठोस प्रकारों को दी जाती है।

मैंने आपके संक्षिप्त उदाहरण का उपयोग करके एक प्रकार का इरेज़र बनाया है और अंत में कुछ परीक्षण कोड जोड़ा है। मैंने प्रोटोकॉल में String का निरंतर प्रकार जोड़ा है और विभिन्न परिदृश्यों का परीक्षण करने में सक्षम होने के लिए दो अनुरूप प्रकार (structs प्रदर्शन उद्देश्यों के लिए सबसे आसान हैं) बनाए हैं।

https://khawerkhaliq.com/blog/swift-protocols-equatable-part-two/

कोड के नीचे समानता तुलना है कि आप को लागू करना चाहते थे समर्थन करना चाहिए:

प्रकार विलोपन प्रयुक्त पद्धति का एक विस्तृत विवरण के लिए, ऊपर ब्लॉग पोस्ट का हिस्सा दो की जाँच करें। आपको प्रोटोकॉल प्रकार को एक प्रकार इरेज़र इंस्टेंस में लपेटना होगा।

protocol X { 
    var name: String { get } 
    func isEqualTo(_ other: X) -> Bool 
    func asEquatable() -> AnyEquatableX 
} 

extension X where Self: Equatable { 
    func isEqualTo(_ other: X) -> Bool { 
     guard let otherX = other as? Self else { return false } 
     return self == otherX 
    } 
    func asEquatable() -> AnyEquatableX { 
     return AnyEquatableX(self) 
    } 
} 

struct Y: X, Equatable { 
    let name: String 
    static func ==(lhs: Y, rhs: Y) -> Bool { 
     return lhs.name == rhs.name 
    } 
} 

struct Z: X, Equatable { 
    let name: String 
    static func ==(lhs: Z, rhs: Z) -> Bool { 
     return lhs.name == rhs.name 
    } 
} 

struct AnyEquatableX: X, Equatable { 
    var name: String { return value.name } 
    init(_ value: X) { self.value = value } 
    private let value: X 
    static func ==(lhs: AnyEquatableX, rhs: AnyEquatableX) -> Bool { 
     return lhs.value.isEqualTo(rhs.value) 
    } 
} 

// instances typed as the protocol 
let y: X = Y(name: "My name") 
let z: X = Z(name: "My name") 
let equalY: X = Y(name: "My name") 
let unequalY: X = Y(name: "Your name") 

// equality tests 
print(y.asEquatable() == z.asEquatable())   // prints false 
print(y.asEquatable() == equalY.asEquatable())  // prints true 
print(y.asEquatable() == unequalY.asEquatable()) // prints false 

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

उम्मीद है कि इससे मदद मिलती है।

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