需要扩展哪些协议以允许===运算符为泛型类型? (错误:二进制运算符'==='不能应用于两个'T'操作数)

时间:2016-04-10 14:58:55

标签: swift generics

我收到编译错误:

  

二元运算符'==='不能应用于两个'T'操作数

其中T是泛型类型,我只是比较两个类型为T的项目。

所以我认为我需要告诉它,通过使T扩展协议,可以在T上使用===运算符。如果是==我会使用Equatable,但我无法看到我应该用于身份比较。

或者有解决方法吗?

编辑:

以下是说明问题的示例代码。我在这里添加了'AnyObject',它在实例化类时导致编译错误。如果删除'AnyObject',则会在'==='上导致错误。

import Foundation

protocol Messenger : AnyObject {
    func notify();
}

class PostOffice<T : AnyObject> {
    var messengers : [T] = []

    func addMessenger(messenger : T) {
        messengers.append(messenger)
    }

    func deleteMessenger(messenger : T) {
        for i in 0 ..< messengers.count {
            if messengers[i] === messenger {    // error if AnyObject not used
                messengers.removeAtIndex(i)
                return
            }
        }
    }

    func handleDelivery(messenger : T) {} // to be overridden

    func deliver() {
        for messenger in messengers {
            handleDelivery(messenger)
        }
    }
}

let p : PostOffice<Messenger> = PostOffice<Messenger>()  // error if AnyObject used

这种情况下的错误是:

  

使用'Messenger'作为符合'AnyObject'的具体类型不支持。

2 个答案:

答案 0 :(得分:2)

如果你看一下public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool 的定义方式:

public func ===<L : AnyCollectionType, R : AnyCollectionType>(lhs: L, rhs: R) -> Bool

T

您可以看到确保AnyObject符合AnyCollectionTypefunc f<T : AnyObject>(a: T, b: T) -> Bool { return a === b } 的要求。例如:

func f<T : AnyCollectionType>(a: T, b: T) -> Bool {
    return a === b
}

{{1}}

答案 1 :(得分:1)

您正在以一种无意义的方式混合泛型和协议。

class PostOffice<T : AnyObject> {

这意味着您希望PostOffices成为某些特定类型的包装器。不是“任何符合这种和这样的协议的类型”,而是一种类型,一种类型。好的,没关系。

let p : PostOffice<Messenger> = PostOffice<Messenger>()  // error if AnyObject used

这表示您希望p成为PostOffice,它包含恰好符合Messenger的任何类型。好吧,那不是你想要的PostOffice。你说你希望它是类型专用的。那是什么?

根据您的命名,我假设您确实希望PostOffice接受任何Messenger。那没关系,但那不应该是通用的:

class PostOffice {
    var messengers : [Messenger] = []

    func addMessenger(messenger : Messenger) {
        messengers.append(messenger)
    }

    func deleteMessenger(messenger : Messenger) {
        for i in 0 ..< messengers.count {
            if messengers[i] === messenger {    // error if AnyObject not used
                messengers.removeAtIndex(i)
                return
            }
        }
    }
    func handleDelivery(messenger : Messenger) {} // to be overridden

    func deliver() {
        for messenger in messengers {
            handleDelivery(messenger)
        }
    }
}

那就是说,你没有在任何地方使用notify(),这听起来你真的希望PostOffice能够在非信使上工作。 (不确定这有用,但它似乎是你写的)。那也没关系,但是你需要一些你专注于PostOffice的实际类型(不是协议):

class SomeMessenger: Messenger {
    func notify() {}
}

let p = PostOffice<SomeMessenger>()

如果您的意思是PostOffice应该是专门的,但在这种情况下您希望接受任何类型的Messenger,那么您需要type-erasure以便您可以创建具体类型包裹Messenger

final class AnyMessager: Messenger {
    let _notify: () -> Void
    init(messenger: Messenger) {
        _notify = messenger.notify
    }
    func notify() { _notify() }
}

let p = PostOffice<AnyMessager>()

(这是许多Swift协议问题的解决方案,但在这种情况下感觉不对。我怀疑你真的希望PostOffice要求Messenger。但我不是真的理解你的PostOffice类型。它将泛型与抽象类混合在一起,这并不是很真实。我怀疑你真的想重新设计这些类型。)

您可能对this implementation of an Observable感兴趣。它显示了一种注册和删除侦听器的不同方法,无需===notify方法。