【问题标题】:Comparing protocol references比较协议参考
【发布时间】:2014-08-04 10:10:29
【问题描述】:

我有一系列协议。现在我想通过使用数组查找协议的索引来从数组中删除一个项目。但是,当将协议对象与数组中的项目进行比较时,编译器会发出警告:

'Protocol' 不符合 AnyObject

protocol SomeProtocol {}
var list:[SomeProtocol] = []
func add(some:SomeProtocol) { list+=some }
func remove(some:SomeProtocol) {
    var index = -1
    for i in 0...list.count-1 { if [i] === some { index = i } }
    if index >= 0 { list.removeAtIndex(index) }
}

【问题讨论】:

  • 并非所有类型都支持===== 运算符

标签: arrays swift compare protocols


【解决方案1】:

如果您只为协议派生类,您可以将协议定义更改为:

protocol SomeProtocol: class {}

然后您将能够使用此协议的引用。

【讨论】:

    【解决方案2】:

    首先,add 超级简单,只需包含这个函数即可:

    func +=(inout lhs: [SomeProtocol], rhs: SomeProtocol) {
        lhs.append(rhs)
    }
    

    remove 比较棘手,因为SomeProtocol 可以同样适用于classstruct,并且只有具有类类型的值才能与=== 进行比较。

    我们可以改用== 运算符,但它只接受符合Equatable 协议的值,并且Equatable 只能用作通用 约束(到目前为止) , 否则你可以使用 protocol<SomeProtocol,Equatable> 之类的东西作为你的数组元素类型。

    如果您确定您的SomeProtocol应用于类,请考虑重构您的代码以使用该类类型:

    protocol SomeProtocol {}
    class SomeClass : SomeProtocol {}
    
    var list:[SomeClass] = []
    
    func add(some:SomeClass) {
        list += some
    }
    
    func remove(some:SomeClass) {
        list -= some
    }
    
    func +=(inout lhs: [SomeClass], rhs: SomeClass) {
        lhs.append(rhs)
    }
    
    func -=(inout lhs: [SomeClass], rhs: SomeClass) {
        for (i,v) in enumerate(lhs) {
            if v === rhs {
                lhs.removeAtIndex(i)
                break
            }
        }
    }
    

    如果你也让SomeClass符合Equatable,那么通常的数组函数会自动工作,你甚至不需要重载+=-=

    否则,如果您不知道您的值是类还是结构体,最好考虑一下 SomeProtocol 的值“相等”意味着什么并需要比较方法:

    protocol SomeProtocol {
        func isEqualTo(some: SomeProtocol) -> Bool
    }
    
    func -=(inout lhs: [SomeProtocol], rhs: SomeProtocol) {
        for (i,v) in enumerate(lhs) {
            if v.isEqualTo(rhs) {
                lhs.removeAtIndex(i)
                break
            }
        }
    }
    
    // add functions work the same as above
    

    或者,您可以使用您的原始代码并编写一个全局比较函数:

    func ===(lhs: SomeProtocol, rhs: SomeProtocol) -> Bool {
        // return something based on the properties of SomeProtocol
    }
    

    【讨论】:

      【解决方案3】:

      我最终在我的协议中使用 isEqual(to: ) 来测试实例比较:

      public protocol fooProtocol {
          ...
          func isEqual(to: fooProtocol) -> Bool
      }
      
      public extension fooProtocol {
          func isEqual(to: fooProtocol) -> Bool {
              let ss = self as! NSObject
              let tt = to as! NSObject
              return ss === tt
          }
      }
      

      似乎对我有用。

      【讨论】:

      • 我认为转换为 NSObject 是危险的,因为该协议可能用于结构。那么演员阵容就会失败。所以我建议使用@Oleg Gordeev 的答案来明确课堂意图。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-30
      • 1970-01-01
      • 2012-07-31
      相关资源
      最近更新 更多