【问题标题】:Swift function taking generic arraySwift函数采用通用数组
【发布时间】:2017-07-24 01:55:16
【问题描述】:

我正在尝试编写一个简单的手动函数来展平嵌套数组。我的代码可以作为 switch 语句正常工作,但当我在“for i in 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] 类型,所以我不得不将“data”变量作为 [data] 传递回其中。这只是强制函数不断解包数组,它只是卡在循环中。关于如何避免这种情况的任何建议?

【问题讨论】:

标签: arrays swift generics infinite-loop


【解决方案1】:

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

该错误相对容易解决 - 只需将 Array 替换为 Array&lt;Any&gt;,即可:

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 条件是true,所以data 的类型确实是Array&lt;Any&gt;,因此[data] 的值必须是Array&lt;Array&lt;Any&gt;&gt;。相反,我们想传入data,它已经是一个数组。

你说你写[data]的原因是因为参数必须是一个数组,所以你被编译器“强迫”了。事实上,编译器强迫你做的唯一一件事就是传入一个类型被声明为Array&lt;Any&gt; 的参数。我们已经确定data 是一个使用if 语句的数组,但data 仍然声明Any(因为它是input 的一个元素,它是Array&lt;Any&gt;),所以编译器不知道它真的是一个数组。

解决方案是 - 将 data 转换为 Array&lt;Any&gt;,而不是使用 if data is Array&lt;Any&gt; 暂时确定 data 是否是一个数组,而是立即丢弃该信息。

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

通过这样做,在if 语句的true 情况下,我们可以访问类型为Array&lt;Any&gt; 的值dataArray - 与仅声明为Anydata 不同。然后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&lt;Any&gt; 当然等同于[Any],所以if 语句可以用那种(通常首选的)语法来编写,如下所示:

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

此外,如果您只是迭代数组,则无需经历整个 for i in 0..&lt;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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    • 2021-11-19
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多