37

从 Swift 2.0 开始,我们似乎可以更接近适用于谓词情况的泛型类型的扩展。

虽然我们仍然不能这样做:

protocol Idable {
    var id : String { get }
}

extension Array where T : Idable {
    ...
}

...我们现在可以这样做:

extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
    ...
    }
}

...并且 Swift 在语法上接受它。但是,对于我来说,当我填写示例函数的内容时,我无法弄清楚如何让编译器满意。假设我要尽可能明确:

extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
        return self.filter { (item : T) -> Bool in
            return item.id == id
        }
    }
}

...编译器将不接受提供给过滤器的闭包,抱怨

无法使用类型为“((T)-> Bool)”的参数列表调用“过滤器”

如果 item 被指定为 Idable,则类似。有人在这里有运气吗?

4

1 回答 1

59
extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
    ...
    }
}

定义了一个泛型方法filterWithId(),其中泛型占位符T被限制为Idable. 但是该定义引入了一个T 与数组元素类型完全无关的本地占位符T (并将其隐藏在方法的范围内)。

所以你没有指定数组元素必须符合Idable,这就是为什么你不能 self.filter() { ... }用期望元素的闭包调用的原因Idable

从 Swift 2 / Xcode 7 beta 2 开始,您可以在泛型类型上定义扩展方法,这对模板有更多限制(比较Array extension to remove object by value以解决非常相似的问题):

extension Array where Element : Idable {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

或者,您可以定义协议扩展方法

extension SequenceType where Generator.Element : Idable {

    func filterWithId(id : String) -> [Generator.Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

如果序列元素类型符合 ,则thenfilterWithId()可用于符合SequenceType(特别是)的所有类型。ArrayIdable

Swift 3中,这将是

extension Sequence where Iterator.Element : Idable {

    func filterWithId(id : String) -> [Iterator.Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}
于 2015-06-10T02:48:35.670 回答