【问题标题】:Swift "where" Array ExtensionsSwift“where”数组扩展
【发布时间】:2015-08-25 02:32:57
【问题描述】:

从 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,则类似。有人在这里碰运气吗?

【问题讨论】:

    标签: swift where-clause swift-extensions


    【解决方案1】:
    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
            }
        }
    }
    

    【讨论】:

    • 有没有办法使用非协议类型,比如extension Array where Iterator.Element : CGRect
    • @BenLeggiero:您可以定义一个extension Sequence where Iterator.Element == CGRect { },即用于一个协议,但ArrayElement 类型只能限制为一个协议。将来可能会改变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多