问题描述
我正在网上学习Swift的学习方法。以下代码是一个测试用例,用于说明在递归情况下调用函数的重载版本的问题。
import Foundation
//Solution goes in Sources
extension Array where Element: Comparable {
func accumulate (_ acc: (Element) throws -> Element) rethrows -> [Element] {
var newArray : [Element]?
try self.forEach{try newArray?.append(acc($0))}
return newArray!
}
func accumulate (_ acc: (Element) throws -> [Element]) rethrows -> [[Element]] {
var newArray : [[Element]]?
try self.forEach{try newArray?.append(acc($0))}
return newArray!
}
}
let input = ["a","b","c"]
let expected = [
["a1","a2","a3"],["b1","b2","b3"],["c1","c2","c3"]
] // The expected result of the statement on the bottom of this code
func recurse(_ input: String) -> [String] {
func appendTo(_ innerInput: String) -> String {
return input+innerInput
}
let result = ["1","2","3"].accumulate(appendTo)
print("3")
return result
}
let result = input.accumulate(recurse)
Fatal error: Unexpectedly found nil while unwrapping an Optional value
Current stack trace:
0 libswiftCore.so 0x00007fa0d799c920 _swift_stdlib_reportFatalError + 69
1 libswiftCore.so 0x00007fa0d78aaa06 <unavailable> + 3279366
2 libswiftCore.so 0x00007fa0d78aad85 <unavailable> + 3280261
3 libswiftCore.so 0x00007fa0d76d2810 _fatalErrorMessage(_:_:file:line:flags:) + 19
4 main 0x000055df0a54ef3a <unavailable> + 7994
5 main 0x000055df0a54e63e <unavailable> + 5694
6 libc.so.6 0x00007fa0d6052ab0 __libc_start_main + 231
7 main 0x000055df0a54e09a <unavailable> + 4250
exited,illegal instruction
请告诉我我的代码有什么问题并解释原因。
非常感谢您!
解决方法
您遇到的问题与过载本身无关。您尝试强制展开的每个变体中都只有newArray = nil
,例如:
func accumulate (_ acc: (Element) throws -> Element) rethrows -> [Element] {
var newArray : [Element]? // here,newArray = nil
// newArray is still nil,and newArray?.append does nothing
try self.forEach{try newArray?.append(acc($0))}
// new array is still nil,and you force unwrap nil,hence Unexpectedly found nil while unwrapping an Optional value
return newArray!
}
要解决此问题,您可以仅在开始时为newArray
分配一些值:
var newArray : [Element] = []
如果您仍在学习敏捷,我建议您采用“绝对不要解包(除非完全必要)”规则。另外,我建议也不要强制转换。您几乎可以随时重写代码,而无需强行拆包/投射。
,有几件事要注意:
- 这里最直接的问题是,您要强制展开
newArray
,这是一个可选的var,您使用nil进行了初始化,但是从不分配非nil值。 - 您必须重载
accumulate
,但是它们可以与泛型合并。 - 您的
accumulate
实际上是map
。术语“累积”通常与reduce
/fold
操作相关。 - 您的
appendTo(_:)
函数很奇怪。- 根据Swift的命名约定,它应该为
append(to:)
。但这没有意义,因为arg不是附加到的东西,而是附加了的东西。我建议将其命名为append(_:)
。 - 仅直接使用
+
运算符不会带来太多价值
- 根据Swift的命名约定,它应该为
- 您的
recurse
函数实际上从未递归。
这是我的写法:
import Foundation
//Solution goes in Sources
extension Array where Element: Comparable {
func myMap<T>(_ transform: (Element) throws -> T) rethrows -> [T] {
var newArray = [T]()
newArray.reserveCapacity(self.count)
for element in self {
try newArray.append(transform(element))
}
return newArray
}
}
let input = ["a","b","c"]
let expected = [
["a1","a2","a3"],["b1","b2","b3"],["c1","c2","c3"],]
func nameMeBetter(_ input: String) -> [String] {
return ["1","2","3"].myMap { input + $0 }
}
let result = input.myMap(nameMeBetter)
print(result)
由于myMap(_:)
与内置Sequence.map(_:)
相同,因此我们可以直接使用它。
所有这些代码都可以简化为:
let input = ["a",]
let result = input.map { char in
["1","3"].map { digit in
char + digit
}
}
print(result)