Swift 调用使用和不使用默认参数声明的函数会导致不同的结果?
我写这段代码是为了在操场上进行测试(学习):Swift 调用使用和不使用默认参数声明的函数会导致不同的结果?,swift,Swift,我写这段代码是为了在操场上进行测试(学习): import Cocoa func DoIt(a: Int, b: Int, c :Int = 0) -> Int { return a + b + c; } func DoIt(a: Int, b: Int, c :NSObject) -> Int { return a * b * c.description.lengthOfBytesUsingEncoding(NSUTF8StringEncoding); } 当我使
import Cocoa
func DoIt(a: Int, b: Int, c :Int = 0) -> Int {
return a + b + c;
}
func DoIt(a: Int, b: Int, c :NSObject) -> Int {
return a * b * c.description.lengthOfBytesUsingEncoding(NSUTF8StringEncoding);
}
当我使用它时,我得到了这个:
DoIt(4, 5, 6); // result: 20
var obj = NSObject(); // result: NSObject
DoIt(4, 5, obj); // result: 520
我期望在执行DoIt(4,5,6)时调用第一个函数DoIt(Int,Int,Int)
代码>但显然另一个正在被调用。6
去了哪里?看起来6
被隐式转换为NSObject
,在objective-c中至少会发出警告。
为什么会这样
奇怪的是,如果我将最后一个c:Int
设置为必需(通过删除=0
),那么它将按预期工作
DoIt(4, 5, 6); // result: 15
var obj = NSObject(); // result: NSObject
DoIt(4, 5, obj); // result: 520
Edit1:添加了IR
如果这有助于理解发生了什么,我发出了以下命令,结果显示在gist链接中:
在Swift文件中(增加强调):
具有默认值的参数的外部名称
在大多数情况下,提供(因此需要)一个
具有默认值的任何参数的外部名称。这确保了
如果值为
在调用函数时提供
为了简化此过程,Swift提供了一个自动外部名称
用于具有默认值的任何参数。自动外置
名称与本地名称相同,就好像您编写了散列一样
代码中本地名称之前的符号
那么您的第一个函数声明
func DoIt(a: Int, b: Int, c : Int = 0) -> Int
被编译器视为
func DoIt(a: Int, b: Int, c c : Int = 0) -> Int
第三个参数的外部参数名为“c”。此函数
必须被称为
DoIt(4, 5, c: 6) // result: 15
但是电话
DoIt(4, 5, 6)
与第一个函数的声明不匹配,仅与另一个函数的声明匹配
func DoIt(a: Int, b: Int, c :NSObject) -> Int
(第三个参数自动桥接到NSNumber
,它是一个子类
属于NSObject
)。这就是为什么会得到“意外”的输出
如果将第一个函数的声明更改为
func DoIt(a: Int, b: Int, _ c : Int = 0) -> Int
(其中,表示“无外部参数名称”)
然后您将获得预期的输出:
DoIt(4, 5, 6) // result: 15
reddit上有一条线索,也许有帮助:我不知道为什么它会这样工作,但我不相信这是故意的行为。如果是的话,我会觉得很奇怪。谢谢@SebastianDressler,我刚刚读了这篇文章。我理解隐式装箱(原语到NSNumber)及其相反的拆箱。但我不确定这里的情况是否如此。这一点尚不清楚me@nacho4d是否有可能查看生成的swift IR代码?如果是这样的话,你可以看到这里发生了什么。在这里添加生成的IR输出:这解释了很多事情!。现在我清楚地看到,对于带有optionals参数的函数,我需要使用外部参数名,或者在声明中使用。
)。然而,我仍然不明白Int
如何隐式转换为NSObject
。@nacho4d:Swift自动将某些本机类型(Int、Float、Bool等)桥接到NSNumber,后者是NSObject的一个子类。您可以在“使用Cocoa数据类型”一节中了解更多信息我更新了答案,使之更清楚。
DoIt(4, 5, 6) // result: 15