Swift “where” Array Extensions

删除回忆录丶 提交于 2019-11-30 00:16:33

问题


As of Swift 2.0 it seems we can get closer to extensions of generic types applicable to predicated situations.

Although we still can't do this:

protocol Idable {
    var id : String { get }
}

extension Array where T : Idable {
    ...
}

...we can now do this:

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

...and Swift grammatically accepts it. However, for the life of me I cannot figure out how to make the compiler happy when I fill in the contents of the example function. Suppose I were to be as explicit as possible:

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

...the compiler will not accept the closure provided to filter, complaining

Cannot invoke 'filter' with an argument list of type '((T) -> Bool)'

Similar if item is specified as Idable. Anyone had any luck here?


回答1:


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

defines a generic method filterWithId() where the generic placeholder T is restricted to be Idable. But that definition introduces a local placeholder T which is completely unrelated to the array element type T (and hides that in the scope of the method).

So you have not specified that the array elements must conform to Idable, and that is the reason why you cannot call self.filter() { ... } with a closure which expects the elements to be Idable.

As of Swift 2 / Xcode 7 beta 2, you can define extension methods on a generic type which are more restrictive on the template (compare Array extension to remove object by value for a very similar issue):

extension Array where Element : Idable {

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

Alternatively, you can define a protocol extension method:

extension SequenceType where Generator.Element : Idable {

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

Then filterWithId() is available to all types conforming to SequenceType (in particular to Array) if the sequence element type conforms to Idable.

In Swift 3 this would be

extension Sequence where Iterator.Element : Idable {

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


来源:https://stackoverflow.com/questions/30746190/swift-where-array-extensions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!