【问题标题】:Swift Protocol Implements EquatableSwift 协议实现 Equatable
【发布时间】:2015-11-02 12:14:25
【问题描述】:

我有以下Protocol:

protocol Cacheable {
    //....//
    func identifier() -> String
}

我可以让Cacheable 实现 Equatable 吗?

当我执行以下操作时:

extension Cacheable: Equatable {}

func ==(lhs:Cacheable,rhs:Cacheable) -> Bool {

     return lhs.identifier() == rhs.identifier()
}

我收到此错误消息:协议扩展Cacheable 不能有继承子句

【问题讨论】:

    标签: swift swift2 protocols equatable


    【解决方案1】:

    1) 允许比较两个相同类型的Cacheables

    protocol Cacheable: Equatable {
        //....//
        func identifier() -> String
    }
    
    func ==<T : Cacheable>(lhs: T, rhs: T) -> Bool {
        return lhs.identifier() == rhs.identifier()
    }
    

    优点

    这是最简单的解决方案。

    缺点

    您只能比较两个相同类型的Cacheable 对象。这意味着下面的代码将失败,为了修复它,您需要使 Animal 符合 Cacheable

    class Animal {
    
    }
    
    class Dog: Animal,Cacheable {
        func identifier() -> String {
            return "object"
        }
    }
    
    class Cat: Animal,Cacheable {
        func identifier() -> String {
            return "object"
        }
    }
    
    let a = Dog()
    
    let b = Cat()
    
    a == b //such comparison is not allowed
    

    2) 允许比较任何类型的Cacheables

    protocol Cacheable:Equatable {
        //....//
        func identifier() -> String
    }
    
    func ==<T:Cacheable>(lhs: T, rhs: T) -> Bool {
        return lhs.identifier() == rhs.identifier()
    }
    
    func !=<T:Cacheable>(lhs: T, rhs: T) -> Bool {
        return lhs.identifier() != rhs.identifier()
    }
    
    func ==<T:Cacheable, U:Cacheable>(lhs: T, rhs: U) -> Bool {
        return lhs.identifier() == rhs.identifier()
    }
    
    func !=<T:Cacheable, U:Cacheable>(lhs: T, rhs: U) -> Bool {
        return lhs.identifier() != rhs.identifier()
    }
    

    优点

    消除上述解决方案 1 的限制。现在您可以轻松比较 DogCat

    缺点

    • 实施时间更长。实际上我不确定为什么只指定 == 函数是不够的——这可能是编译器的错误。无论如何,您必须为==!= 提供实现。
    • 在某些情况下,这种实现的好处也可能会带来问题,因为您允许在完全不同的对象之间进行比较,编译器完全可以接受。

    3) 不符合Equatable

    protocol Cacheable {
        //....//
        func identifier() -> String
    }
    
    func ==(lhs: Cacheable, rhs: Cacheable) -> Bool {
        return lhs.identifier() == rhs.identifier()
    }
    
    func !=(lhs: Cacheable, rhs: Cacheable) -> Bool {
        return lhs.identifier() != rhs.identifier()
    }
    

    优点

    您可以使用Cacheable 作为类型而不需要任何泛型。这引入了一系列全新的可能性。例如:

    let c:[Cacheable] = [Dog(),RaceCar()]
    
    c[0] == c[1]
    c[0] != c[1]
    

    使用解决方案 1 和 2,此类代码将失败,您必须在类中使用泛型。但是,在最新的实现中,Cacheable 被视为一种类型,因此您可以声明一个类型为 [Cacheable] 的数组。

    缺点

    您不再声明符合Equatable,因此任何接受Equatable 参数的函数都不会接受Cacheable。显然,除了==!=,我们为Cacheables 声明了它们。

    如果这不是您的代码中的问题,我实际上更喜欢这种解决方案。在许多情况下,能够将协议视为一种类型非常有用。

    【讨论】:

    • 我以前做过,我得到了:Binary operator '==' cannot be applied to two Cacheable operands 尝试比较两个对象实现时Cacheable
    • 这就是我使用泛型的原因;)这段代码有效。我现在已经用 Xcode 7 beta 5 测试了它
    • 不要使用游乐场。尝试将其放入代码中。将其放入您的一个应用程序的 AppDelegate 并在 willFinishLaunching 函数中检查它
    • 这应该是被接受的答案。在 swift 2.1 中完美运行
    • 不起作用。我认为这是因为 lhs 和 rhs 可能属于不同的类型,并且 swift 无法判断您是否正在检查不同的类型。示例:Type1() 和 Type2 都符合 Cacheable。现在尝试 Type1() as Cacheable == Type2() as Cacheable -> Error。不能应用于两个可缓存类型的操作数。
    【解决方案2】:

    试试吧。

    extension Equatable where Self : Cacheable {
    }
    

    【讨论】:

    • 这似乎不起作用:我定义了一个类 class MyClass : Cacheable { ... } 并尝试将该类的一个实例传递给一个函数 func foo&lt;T : Equatable&gt;(obj : T) 并且没有编译。 (顺便说一句:由于不起作用,后来发布并删除了相同的解决方案。)
    • 同理,无法将二进制运算符 '==' 应用于两个 'SubtitleTrack' 操作数,其中 SubtitleTrack 是使用此扩展的协议 :(
    猜你喜欢
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多