首先,您在相当复杂的情况下使用三元运算符 (?:)。如果您首先修改代码以改用 if 语句,则在调用 outputArray.append(data) - Generic parameter 'Element' could not be inferred 时出现的编译器错误会出现在更合理的位置(即 if 语句的行) .
该错误相对容易解决 - 只需将 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 条件是true,所以data 的类型确实是Array<Any>,因此[data] 的值必须是Array<Array<Any>>。相反,我们想传入data,它已经是一个数组。
你说你写[data]的原因是因为参数必须是一个数组,所以你被编译器“强迫”了。事实上,编译器强迫你做的唯一一件事就是传入一个类型被声明为Array<Any> 的参数。我们已经确定data 是一个使用if 语句的数组,但data 仍然声明为Any(因为它是input 的一个元素,它是Array<Any>),所以编译器不知道它真的是一个数组。
解决方案是 - 将 data 转换为 Array<Any>,而不是使用 if data is Array<Any> 暂时确定 data 是否是一个数组,而是立即丢弃该信息。
新的if 语句变为if let dataArray = data as? Array<Any>。语句data as? Array<Any> 尝试将data 转换为数组,如果成功则返回Array<Any> 类型的值,否则返回nil。然后if let dataArray = ... 语句将值存储在dataArray 中,如果给定非nil 值,则返回true,如果给定nil 值,则返回false(这称为条件绑定)。
通过这样做,在if 语句的true 情况下,我们可以访问类型为Array<Any> 的值dataArray - 与仅声明为Any 的data 不同。然后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
}