比较协议引用

9
我有一个协议数组,现在我想通过查找该数组中协议的索引来从数组中删除一个项目。然而,当将协议对象与数组中的项进行比较时,编译器会发出警告:
“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) }
}

1
不是所有类型都支持 ===== 运算符。 - newacct
3个回答

21

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

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
}

0

最终我在协议中使用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的答案来明确仅限类的意图。 - Minding

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接