Aleksei Danilov
Aleksei Danilov

Reputation: 645

error: generic parameter 'T' could not be inferred in swift

I have function which make flatted array from nested array. It works perfectly for int array.

let array: [Any] = [1, 2, [3]]

func makeFlatArray(_ array: [Any]) -> [Int] {
    var flatArray = [Int]()
    for item in array {
        if let item = item as? Int {
            flatArray.append(item)
        } else if let item = item as? [Any] {
            let result = makeFlatArray(item)
            flatArray += result
        }
    }
    return flatArray
}

But I want make it generic and I have got error when trying.

func makeFlatArrayGeneric<T>(_ array: [Any]) -> [T] {
    var flatArray = [T]()
    for item in array {
        if let item = item as? T {
            flatArray.append(item)
        } else if let item = item as? [Any] {
            let result = makeFlatArrayGeneric(item)
            flatArray += result
        }
    }
    return flatArray
}

Error:

Playground execution failed:

error: FlatNestedArraysExample.playground:22:26: error: generic parameter 'T' could not be inferred
            let result = makeFlatArrayGeneric(item)
                         ^

FlatNestedArraysExample.playground:16:6: note: in call to function 'makeFlatArrayGeneric'
func makeFlatArrayGeneric<T>(_ array: [Any]) -> [T] {

Upvotes: 4

Views: 12168

Answers (2)

Yannick
Yannick

Reputation: 3278

You have to tell the compiler the type of T.

func makeFlatArrayGeneric<T>(_ array: [Any]) -> [T] {
    var flatArray = [T]()
    for item in array {
        if let item = item as? T {
            flatArray.append(item)
        } else if let item = item as? [Any] {
            let result: [T] = makeFlatArrayGeneric(item)
            flatArray += result
        }
    }
    return flatArray
}

let array: [Any] = [1, 2, [3], [4, [5]]]
let items: [Int] = makeFlatArrayGeneric(array) //[1, 2, 3, 4, 5]

A more functional approach to solving your problem.

extension Array {
    func flatten() -> Array<Element> {
        return self.flatMap({ element -> [Element] in
            if let array = element as? Array {
                return array.flatten()
            } else {
                return [element]
            }
        })
    }
}

let items: [Int] = array.flatten() //[1, 2, 3, 4, 5]

Upvotes: 12

Sweeper
Sweeper

Reputation: 272685

You gotta do something to make swift aware what is T, one way to do this is to assign the return value to a variable whose type is known:

let result: [T] = makeFlatArrayGeneric(item)

Another way is to pass the type as a parameter:

func makeFlatArrayGeneric<T>(_ array: [Any], type: T.Type) -> [T] {
    var flatArray = [T]()
    for item in array {
        if let item = item as? T {
            flatArray.append(item)
        } else if let item = item as? [Any] {
            let result = makeFlatArrayGeneric(item, type: type)
            flatArray += result
        }
    }
    return flatArray
}

And call it like this:

makeFlatArrayGeneric(yourArray, type: Int.self)

Upvotes: 5

Related Questions