Swift调用非可选参数函数省略实参未编译报错且返回异常类型问题
问题背景
测试Swift代码时发现异常行为,定义函数如下:
func makeIncrementer(number: Int) -> ((Int) -> Int) { func incrementer(inputNumber: Int) -> Int { return inputNumber+1 } return incrementer }
注:number参数未被使用,这是无意的错误,却引发了此异常行为。
正常调用let functionVariable = makeIncrementer(number: 7)时,输出(Function)和8,符合预期;但当调用写成let functionVariable = makeIncrementer(number: )时,Xcode未报错,编译运行后输出两次(Function)。
问题解答
1. 非可选参数为何能省略实参编译通过?
这是Swift的**部分应用(partial application)**特性导致的。当你写makeIncrementer(number: )时,并不是省略了实参,而是将原函数转换为一个等待接收剩余参数的新函数:原函数签名是(Int) -> ((Int) -> Int),部分应用后得到的新函数签名是(Int) -> ((Int) -> Int)——也就是你需要再给这个新函数传入一个Int值,它才会返回原本的incrementer函数。
因为原函数内部没有使用number参数,Swift允许这种写法,即使参数是非可选类型。部分应用本质是把多参数函数拆解成嵌套的单参数函数,这里相当于把makeIncrementer变成了一个“先接收number,再返回增量函数”的函数。
2. 为何会出现两个函数类型的对象?
当你执行let functionVariable = makeIncrementer(number: )时,functionVariable本身就是一个函数(类型为(Int) -> ((Int) -> Int)),打印它会输出(Function);当你调用这个函数(比如let innerFunc = functionVariable(7)),它会返回原函数内部的incrementer函数(类型为(Int) -> Int),再打印innerFunc又会输出一次(Function)。这就是你看到两次输出的原因——这是两个不同的函数对象:外层的部分应用函数,以及它返回的内层增量函数。
如果原函数内部使用了number参数(比如return inputNumber + number),makeIncrementer(number: )的写法依然合法,但此时必须给返回的外层函数传入Int值,才能得到绑定了对应number的增量函数。
内容的提问来源于stack exchange,提问作者Vojta

