Swift“where”数组扩展

时间:2015-06-10 02:42:26

标签: swift where-clause swift-extensions

从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) - &gt; Bool)”的参数列表调用“过滤器”

类似if if指定为Idable。这里有人有运气吗?

1 个答案:

答案 0 :(得分:43)

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

定义泛型方法filterWithId() 占位符T仅限Idable。但是这个定义引入了一个本地占位符T 这与数组元素类型T完全无关 (隐藏在方法范围内)。

所以你有 not 指定数组元素必须符合 到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
        }
    }
}

然后filterWithId()适用于所有符合要求的类型 如果序列元素,则SequenceType(特别是Array) 类型符合Idable

Swift 3 中,这将是

extension Sequence where Iterator.Element : Idable {

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