2016-10-07 8 views
10

मैं एक आधार वर्ग में (Equatable से) == ऑपरेटर को लागू करने की कोशिश कर रहा हूँ और स्विफ्ट 3. वर्गों के सभी में अपनी उपवर्गों केवल स्विफ्ट में इस्तेमाल किया जाएगा तो मैं NSObject या NSCopying प्रोटोकॉल शामिल करने के लिए नहीं करना चाहती।कक्षा पदानुक्रम में समतुल्य प्रोटोकॉल को सही तरीके से कार्यान्वित कैसे करें?

class Base { 
    var x : Int 
} 

class Subclass : Base { 
    var y : String 
} 

अब मैं Equatable जोड़ना चाहते थे और Base को == ऑपरेटर:

मैं एक आधार वर्ग और एक उपवर्ग के साथ शुरू कर दिया। काफी सरल लगता है। अब तक

class Base : Equatable { 
    var x : Int 

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

तो अच्छा: प्रलेखन से == ऑपरेटर हस्ताक्षर कॉपी करें। उपवर्ग के लिए अब:

class Subclass : Base { 
    static override func == (lhs: Base, rhs: Base) -> Bool { 
     return true 
    } 
} 

लेकिन यह एक त्रुटि में परिणाम है:

Operator function overrides a 'final' operator function

ठीक है। कुछ शोध के बाद (अभी भी स्विफ्ट 3 सीखना) मैं सीखता हूं कि static को class के साथ प्रतिस्थापित किया जा सकता है ताकि टाइप विधि को ओवरराइड किया जा सके।

तो मैं Base में class को static बदलने का प्रयास:

class Base : Equatable { 
    var x : Int 

    class func == (lhs: Base, rhs: Base) -> Bool { 
     return lhs.x == rhs.x 
    } 
} 

लेकिन यह एक नए त्रुटि में परिणाम है:

Operator '==' declared in non-final class 'Base' must be 'final'

ओह। यह होना चाहिए उससे कहीं अधिक जटिल है।

मैं बेस श्रेणी और उप-वर्ग में Equatable प्रोटोकॉल और == ऑपरेटर को कैसे कार्यान्वित कर सकता हूं?

उत्तर

8

बहुत सारे शोध और कुछ परीक्षण और त्रुटि के बाद मैं अंततः एक कामकाजी समाधान के साथ आया। पहला कदम कक्षा के अंदर से वैश्विक स्तर तक == ऑपरेटर को ले जा रहा था। इसने static और final के बारे में त्रुटियों को ठीक किया।

आधार वर्ग इस बन गया के लिए

:

func == (lhs: Base, rhs: Base) -> Bool { 
    return lhs.x == rhs.x 
} 

class Base : Equatable { 
    var x : Int 
} 

और उपवर्ग के लिए:

func == (lhs: Subclass, rhs: Subclass) -> Bool { 
    return true 
} 

class Subclass : Base { 
    var y : String 
} 

अब केवल एक भाग बाईं पता लगाना है कि कैसे से आधार वर्ग के == ऑपरेटर कॉल करने के लिए उप-वर्ग के == ऑपरेटर। यह मैं अंतिम समाधान को जन्म दिया:

func == (lhs: Subclass, rhs: Subclass) -> Bool { 
    if lhs.y == rhs.y { 
     if lhs as Base == rhs as Base { 
      return true 
     } 
    } 

    return false 
} 

कि आधार वर्ग में == ऑपरेटर के लिए एक कॉल में पहली if बयान का परिणाम है।


अंतिम समाधान:

बेस।तेज:

func == (lhs: Base, rhs: Base) -> Bool { 
    return lhs.x == rhs.x 
} 

class Base : Equatable { 
    var x : Int 
} 

Subclass.swift:

func == (lhs: Subclass, rhs: Subclass) -> Bool { 
    if lhs.y == rhs.y { 
     if lhs as Base == rhs as Base { 
      return true 
     } 
    } 

    return false 
} 

class Subclass : Base { 
    var y : String 
} 
+1

वाह। चालाक काम-आसपास, लेकिन क्या यह वास्तव में स्विफ्ट हमें क्या करता है? –

0

मुझे पता है के बाद से सवाल पोस्ट किया जाता है यह एक समय हो गया है, लेकिन मुझे उम्मीद है कि मेरा उत्तर मदद करता है।

टीएलडीआर - == को ओवरराइड करने का प्रयास करने के बजाय, आप एक कस्टम तुलनात्मक विधि प्रदान करते हैं, == इसे कॉल करें, और यदि आवश्यक हो तो कस्टम तुलनात्मक विधि को ओवरराइड करें।


तो तुम

All of the classes will only be used in Swift so I do not want to involve NSObject or the NSCopying protocol.

लेकिन अगर आप थे NSObject उपवर्ग के लिए, कैसे आप अपने कस्टम तुलना विधि लिखेंगे कहा? आप isEqual(Any?), सही स्थान पर आ जाएगी? और अगर आप अपने उपवर्ग में Equatable प्रोटोकॉल के अनुरूप करने की कोशिश, संकलक के बारे में "प्रोटोकॉल Equatable को निरर्थक अनुरूपता" शिकायत करेगा क्योंकि NSObject पहले से ही Equatable पुष्टि।

अब जब कि हमारे बारे में कैसे NSObject इस समस्या को संभालती है कुछ संकेत देता है - यह एक कस्टम विधि isEqual(Any?) की तुलना प्रदान करता है, यह == अंदर फोन, और उसके उपवर्गों यह ओवरराइड कर सकते हैं यदि आवश्यक हो। आप अपनी खुद की बेस क्लास में भी ऐसा कर सकते हैं।

आगे की हलचल के बिना, चलो कुछ प्रयोगों करना (स्विफ्ट 4 में) करते हैं। कुछ वर्गों

class Grandpa: Equatable { 
    var x = 0 

    static func ==(lhs: Grandpa, rhs: Grandpa) -> Bool { 
     return lhs.isEqual(to: rhs) 
    } 

    func isEqual(to object: Any?) -> Bool { 
     guard object != nil && type(of: object!) == Grandpa.self else { 
      return false 
     } 
     let value = object as! Grandpa 
     return x == value.x 
    } 
} 

class Father: Grandpa { 
    var y = 0 

    override func isEqual(to object: Any?) -> Bool { 
     guard object != nil && type(of: object!) == Father.self else { 
      return false 
     } 
     let value = object as! Father 
     return x == value.x && y == value.y 
    } 
} 

class Son: Father { 
    var z = 0 

    override func isEqual(to object: Any?) -> Bool { 
     guard object != nil && type(of: object!) == Son.self else { 
      return false 
     } 
     let value = object as! Son 
     return x == value.x && y == value.y && z == value.z 
    } 
} 

को परिभाषित करने और कुछ परीक्षण कोड

let grandpa1 = Grandpa() 
let grandpa2 = Grandpa() 
let grandpa3: Grandpa? = nil 
let grandpa4: Grandpa? = nil 
let father1 = Father() 
let father2 = Father() 
let father3 = Father() 
father3.y = 1 
let son1 = Son() 
let son2 = Son() 
let son3 = Son() 
son3.z = 1 

print("grandpa1 == grandpa2: \(grandpa1 == grandpa2)") 
print("grandpa1 == grandpa3: \(grandpa1 == grandpa3)") 
print("grandpa3 == grandpa4: \(grandpa3 == grandpa4)") 
print("grandpa1 == father1: \(grandpa1 == father1)") 
print("father1 == father2: \(father1 == father2)") 
print("father1 == father3: \(father1 == father3)") 
print("son1 == son2: \(son1 == son2)") 
print("son1 == son3: \(son1 == son3)") 

भागो यह लिख सकते हैं और आप मिलना चाहिए

grandpa1 == grandpa2: true 
grandpa1 == grandpa3: false 
grandpa3 == grandpa4: true 
grandpa1 == father1: false 
father1 == father2: true 
father1 == father3: false 
son1 == son2: true 
son1 == son3: false 
+0

1. अपने उपवर्गों में 'isEqual' के कार्यान्वयन सिर्फ उपवर्ग के गुणों की जाँच के बाद' super.isEqual' बुला जाना चाहिए। एक उप-वर्ग को अपने मूल वर्गों के किसी भी गुण की कोई जांच नहीं करनी चाहिए। 2. वास्तव में प्रश्न से संबंधित नहीं है, लेकिन अपने दादा, पिता, पुत्र वर्ग पदानुक्रम पीछे की ओर है। तार्किक रूप से, एक पुत्र पिता नहीं है और पिता एक ग्रैंडपा नहीं है। पुत्र वर्ग रूट वर्ग होना चाहिए। पिता को पुत्र का विस्तार करना चाहिए और ग्रैंडपा को पिता का विस्तार करना चाहिए। – rmaddy

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

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