Swift函数采用泛型数组

时间:2017-03-03 20:12:06

标签: arrays swift generics infinite-loop

我试图编写一个简单的手动滚动函数来展平嵌套数组。我的代码可以作为switch语句正常工作,但是当我在一个"中为i而在0..arr.count"中递归调用它时。环。我查看传入的数组中的每个元素并说"如果这是一个数组,则调用该函数并将其传入,否则追加到输出数组"。

func flatten (input: [Any]) -> [Any] {


    var outputArray = [Any] ()

    for i in 0..<input.count {
        let data = input[i];
        (data is Array) ? outputArray += flatten(input: [data]) : outputArray.append(data)

    }

    return outputArray

}

因为我的函数参数必须是[Any]类型,所以我强制传递&#34;数据&#34;作为[数据]变回它。这只是强制函数不断解压缩数组,它只是卡在循环中。关于如何避免这种情况的任何建议?

1 个答案:

答案 0 :(得分:0)

首先,您在相当复杂的情况下使用三元运算符(?:)。如果您首先修改代码以使用if语句,那么出现在outputArray.append(data) - Generic parameter 'Element' could not be inferred调用中的编译器错误会出现在一个更明智的地方(即if语句的行。)

Generic parameter inference fails

该错误相对容易解决 - 只需将Array替换为Array<Any>,即可向我们提供:

func flatten(input: [Any]) -> [Any] {
    var outputArray = [Any]()

    for i in 0..<input.count {
        let data = input[i]
        if data is Array<Any> {
            outputArray += flatten(input: [data])
        } else {
            outputArray.append(data)
        }
    }

    return outputArray
}

此时,原始问题仍然存在,因为传递给flatten(input:)的值为[data]。我们知道,由于if条件为truedata实际上属于Array<Any>类型,因此值[data]必须是Array<Array<Any>>。相反,我们想要传入data,这已经是一个数组。

你说你写[data]的原因是因为参数必须是一个数组,所以你被编译器“强迫”了。实际上,编译器强制要求你做的唯一事情是传入一个声明为Array<Any>类型的参数。我们确保data是使用if语句的数组,但data仍然声明Any(因为它是input的元素,它是Array<Any>),因此编译器不知道它实际上是一个数组。

解决方案是 - 而不是使用if data is Array<Any>来暂时确定data是否是一个数组,而是立即抛出该信息 - 将data转换为Array<Any>。< / p>

新的if语句变为if let dataArray = data as? Array<Any>。语句data as? Array<Any>尝试将data转换为数组,如果成功则返回类型Array<Any>,否则返回nil。然后if let dataArray = ...语句将值存储在dataArray中,如果给定非true值则返回nil,如果给定false,则返回nil } value(这称为条件绑定)。

通过这样做,在true语句的if案例中,我们可以访问类型为dataArray的值Array<Any> - 与data不同,仅声明为Any。然后dataArray可以传递到flatten(input:),并且不会嵌套在另一个Array内。

func flatten(input: [Any]) -> [Any] {
    var outputArray = [Any]()

    for i in 0..<input.count {
        let data = input[i]
        if let dataArray = data as? Array<Any> {
            outputArray += flatten(input: dataArray)
        } else {
            outputArray.append(data)
        }
    }

    return outputArray
}

其他几点说明:

Array<Any>当然等同于[Any],因此if语句可以使用该(通常首选)语法编写,如下所示:

if let dataArray = data as? [Any] {
    outputArray += flatten(input: dataArray)
}

此外,如果你只是迭代数组,就没有必要经历整个for i in 0..<input.count { let data = input[i] ...的考验,如下所示:

func flatten(input: [Any]) -> [Any] {
    var outputArray = [Any]()

    for data in input {
        if let dataArray = data as? [Any] {
            outputArray += flatten(input: dataArray)
        } else {
            outputArray.append(data)
        }
    }

    return outputArray
}