2016-10-07 13 views
10

나는 스위프트 3의 기본 클래스와 하위 클래스에 == 연산자 (Equatable)를 구현하려고합니다. 모든 클래스는 Swift에서만 사용되므로 NSObject 또는 NSCopying 프로토콜을 사용하고 싶지 않습니다. 클래스 계층에서 Equatable 프로토콜을 올바르게 구현하는 방법은 무엇입니까?

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

확인을 클릭합니다. 몇 가지 연구 (Swift 3을 배우는 것) 후에 staticclass으로 대체 할 수 있으므로 형식 메서드를 재정의 할 수 있음을 나타냅니다.

그래서 나는 Baseclassstatic을 변경하려고 :

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

많은 연구와 시행 착오 끝에 마침내 해결 방법이 생겼습니다. 첫 번째 단계는 == 연산자를 클래스 내부에서 전역 범위로 이동하는 것이 었습니다. 이로 인해 staticfinal에 대한 오류가 수정되었습니다. 이되었다 기본 클래스에 대한

:

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 문 결과.


최종 해결책 :

자료.SWIFT :

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

나는 질문이 게시 된 이후 오랜만 것을 알고,하지만 난 내 대답이 도움이되기를 바랍니다.

TLDR - ==을 재정의하려는 대신 사용자 지정 비교 방법을 제공하고 ==을 호출하고 필요한 경우 사용자 지정 비교 방법을 재정의합니다.


그래서 당신은

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을 이미 준수했기 때문에 컴파일러는 "Equatable 프로토콜에 대한 중복성 준수"에 대해 불만을 제기합니다. NSObject.

이제는 NSObject이이 문제를 처리하는 방법에 대한 몇 가지 힌트를 제공합니다. 사용자 정의 비교 방법 isEqual(Any?)을 제공하고 == 내에서 호출하며, 필요한 경우 하위 클래스가이를 무시할 수 있습니다. 자신의 기본 클래스에서 동일한 작업을 수행 할 수 있습니다.

더 이상 고심하지 말고 몇 가지 실험을 해보겠습니다 (Swift 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. 질문과 관련이 없지만 GrandPa, Father, Son 클래스 계층 구조는 거꾸로되어 있습니다. 논리적으로, 아들은 아버지가 아니며 아버지는 할아버지가 아닙니다. Son 클래스는 루트 클래스 여야합니다. 아버지는 아들을 넓히고 GrandPa는 아버지를 확장시켜야합니다. – rmaddy