2017-08-13 48 views
1

协议我有一个协议:夫特声明equatable

protocol CustomProtocol { 
    var title: String { get } 
    var subtitle: String { get } 
} 

然后我有2个目的,符合这个网络协议。我想比较他们,所以我想CustomProtocol是Equatable。

protocol CustomProtocol: Equatable { 
    var title: String { get } 
    var subtitle: String { get } 
    static func ==(lhs: Self, rhs: Self) -> Bool 
} 

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

但是这种改变,我得到“协议CustomProtocol只能作为一种通用的约束,因为它具有自我或相关类型requeriments后 我能想到的解决,这是有一个第三个属性一样的唯一途径依赖于他人,比较该物业的哈希值。

enter image description here

Here you have a sample操场上用实际的代码。

+0

您需要从更新的协议声明中删除相等函数,因为它们只在扩展中需要。 – Ollie

+0

比较https://stackoverflow.com/q/41298464/2976878 – Hamish

回答

1

的Equatable protoc ol有一个自我约束来解决这个问题,你应该只能检查相同类型的对象之间的相等性,而不是相同的协议。这就是为什么它有自我要求。否则,你可以说

let a: Equatable = 42 
let b: Equatable = "hello" 

a == b会工作。这会很糟糕,因为你可以比较完全不相关类型的对象。自我需求使得这是一个编译时错误。

如果你想你的对象的协议的基础上比较,只需实现==操作者没有自我要求:

extension CustomProtocol { 
    func == (lhs: CustomProtocol, rhs: CustomProtocol) -> Bool { 
     return lhs.name == rhs.name 
    } 
    func != (lhs: CustomProtocol, rhs: CustomProtocol) -> Bool { 
     return !(lhs == rhs) 
    } 
} 

现在你可以用CustomProtocol型直接宣告你的协议的情况下,并加以比较。

但是在这种情况下协议可能不是正确的抽象。也许你应该把它作为一个抽象类来实现。

+0

我得到'不明确的参考==' – Godfather

+0

当然你的协议不能再从'Equatable'继承。 – Palle

+0

我添加了一个示例Playground,删除继承后也是一样。 – Godfather

0

因为EquatableSelf的要求,所以不应该直接在协议上实现。否则,该协议将作为一种类型不可用。

要在协议级别实现Equatable,但能够使用该协议作为类型,则可以使用类型擦除。

为了演示,我修改了您的操场中给出的代码来构建橡皮擦。

因为我使用的方法的详细说明,请参阅这个职位上我的博客:

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

这里是你的游乐场修改后的代码:

protocol CustomProtocol { 
    var title: String { get } 
    var subtitle: String { get } 
    func isEqualTo(_ other: CustomProtocol) -> Bool 
    func asEquatable() -> AnyEquatableCustomProtocol 
} 

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

struct A: CustomProtocol, Equatable { 
    var title: String 
    var subtitle: String 
    static func ==(lhs: A, rhs: A) -> Bool { 
     return lhs.title == rhs.title && lhs.subtitle == rhs.subtitle 
    } 
} 

struct B: CustomProtocol, Equatable { 
    var title: String 
    var subtitle: String 
    static func ==(lhs: B, rhs: B) -> Bool { 
     return lhs.title == rhs.title && lhs.subtitle == rhs.subtitle 
    } 
} 

struct AnyEquatableCustomProtocol: CustomProtocol, Equatable { 
    var title: String { return value.title } 
    var subtitle: String { return value.subtitle } 
    init(_ value: CustomProtocol) { self.value = value } 
    private let value: CustomProtocol 
    static func ==(lhs: AnyEquatableCustomProtocol, rhs: AnyEquatableCustomProtocol) -> Bool { 
     return lhs.value.isEqualTo(rhs.value) 
    } 
} 

// instances typed as the protocol 
let a: CustomProtocol = A(title: "First title", subtitle: "First subtitle") 
let b: CustomProtocol = B(title: "First title", subtitle: "First subtitle") 
let equalA: CustomProtocol = A(title: "First title", subtitle: "First subtitle") 
let unequalA: CustomProtocol = A(title: "Second title", subtitle: "Second subtitle") 

// equality tests 
print(a.asEquatable() == b.asEquatable())   // prints false 
print(a.asEquatable() == equalA.asEquatable())  // prints true 
print(a.asEquatable() == unequalA.asEquatable()) // prints false 

点需要注意的是,通过这种方法,实际的==比较被委托给底层的具体类型,但我们只处理协议类型以维护抽象。

在这里,我只使用了擦除类型的实例来进行一次比较。但是,由于类型橡皮擦符合CustomProtocol,因此可以在任何需要协议类型的地方保存和使用这些实例。因为它们符合Equatable,所以它们也可以用于任何需要符合要求的地方。

只是为了背景下,这篇文章解释了为什么这是不可取的尝试直接在协议执行Equatable一致性,甚至==功能:

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

因此,类型擦除。

希望这会有所帮助。