Search code examples
swiftgenericsswift-extensions

swift- Cannot convert value of type '[Int]' to expected argument type '[_]'


I'm trying to implement a zip function as an extension to Array, and I'm intending for it to be used like this:

let myKeys = ["a","b","c"]
let myVars = [1,2,3]
myKeys.zip(myVars) // ["a":1,"b":2,"c":3]

Here is my attempt:

extension Array {
    public func zip<T,U>(vals: [U]) -> [T:U] {

        var dict: [T:U] = Dictionary()

        for (i,key) in self.enumerate() {
            if let k = key as? T {
                dict[k] = vals[i]
            }
        }

        return dict
    }
}

let myKeys = ["a","b","c"]
let myVars = [1,2,3]
myKeys.zip(myVars) // ERROR: Cannot convert value of type '[Int]' to expected argument type '[_]'

On the last line I am getting an error that I do not completely understand. I understand it to mean that I'm passing an [Int] and it's expecting an [_]. But isn't _ just a generic placeholder here? Why would it complain about receiving an [Int]?

Also, if I implement zip as a class function it has no issues:

class func zip<T,U>(keys keys: [T], vals: [U]) -> [T:U] {

    var dict: [T:U] = Dictionary()

    for (i,key) in keys.enumerate() {
        dict[key] = vals[i]
    }

    return dict
}

zip(keys: myKeys,vals: myVals) // ["a":1,"b":2,"c":3]

Any thoughts on this would be much appreciated!


Solution

  • Note that Array already has an associated type, it's called Element, so no need to declare T. The problem with your code is that you cannot really convert an Element to undefined type T (there is no connection between T and the array element type).

    extension Array where Element: Hashable {
        public func zip<U>(vals: [U]) -> [Element: U] {
    
            var dict: [Element: U] = Dictionary()
    
            for (i, key) in self.enumerate() {
                dict[key] = vals[i]
            }
    
            return dict
        }
    }
    
    let myKeys = ["a","b","c"]
    let myVars = [1,2,3]
    let map = myKeys.zip(myVars)
    
    print(map)
    

    Also note that I have added Hashable requirement for the keys.