Swift"where"数组扩展

yo.*_*n.g 26 where-clause swift swift-extensions

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

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

protocol Idable {
    var id : String { get }
}

extension Array where T : Idable {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

...和Swift语法接受它.但是,对于我的生活,当我填写示例函数的内容时,我无法弄清楚如何让编译器开心.假设我要尽可能明确:

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

...编译器不会接受提供的过滤,过滤,抱怨

无法使用类型为'((T) - > Bool)'的参数列表调用'filter'

如果将item指定为Idable,则类似.这里有运气吗?

Mar*_*n R 45

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

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

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

从Swift 2/Xcode 7 beta 2开始,您可以在泛型类型上定义扩展方法,这些扩展方法对模板的限制更多(比较数组扩展以按值移除对象以解决非常类似的问题):

extension Array where Element : Idable {

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

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

extension SequenceType where Generator.Element : Idable {

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

然后,如果序列元素类型符合,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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @BenLeggiero:您可以定义一个`扩展序列,其中Iterator.Element == CGRect {}`,即对于协议,但`Element`类型的`Array`只能限制在一个协议中.这可能会在未来发生变化. (3认同)