使用和不使用默认参数声明的调用函数会导致不同的结果?

时间:2022-06-29 21:44:31

I wrote this code for testing (learning) purposes in a playground:

我在操场上编写了用于测试(学习)目的的代码:

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);
}

And when I used it I got this:

当我使用它时,我得到了这个:

DoIt(4, 5, 6);            // result: 20
var obj = NSObject();     // result: NSObject
DoIt(4, 5, obj);          // result: 520

I expected the first function DoIt(Int, Int, Int) called when doing DoIt(4, 5, 6); but apparently the other is being called. Where did the6 go? It looks like the 6 was implicitly converted into an NSObject, In objective-c that would rise a warning at least.
Why is this?

我期待在执行DoIt时调用的第一个函数DoIt(Int,Int,Int)(4,5,6);但显然另一个被称为。 6去了哪里?看起来6被隐式转换为NSObject,在objective-c中至少会引发警告。为什么是这样?

Curiously if I make the last c: Int required (by removing the = 0) then it works as expected.

奇怪的是,如果我需要最后一个c:Int(通过删除= 0),那么它按预期工作。

DoIt(4, 5, 6);            // result: 15
var obj = NSObject();     // result: NSObject
DoIt(4, 5, obj);          // result: 520

Edit1: Added IR
In case this helps to understand what is going on I issued the following command and the result is in the gist link: https://gist.github.com/nacho4d/94fdb72d8a3fee0c09e5

编辑1:添加了IR如果这有助于理解发生了什么,我发出了以下命令,结果在gist链接中:https://gist.github.com/nacho4d/94fdb72d8a3fee0c09e5

$ swiftc \
   -emit-ir /Users/nacho4d/Desktop/function2/function2/main.swift \
   -sdk Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk 

1 个解决方案

#1


4  

From "Functions" in the Swift documentation (emphasis added):

从Swift文档中的“函数”(重点添加):

External Names for Parameters with Default Values

具有默认值的参数的外部名称

In most cases, it is useful to provide (and therefore require) an external name for any parameter with a default value. This ensures that the argument for that parameter is clear in purpose if a value is provided when the function is called.

在大多数情况下,为任何具有默认值的参数提供(因此需要)外部名称是很有用的。这样可以确保在调用函数时提供值时,该参数的参数是有目的的。

To make this process easier, Swift provides an automatic external name for any parameter that has a default value. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code.

为了简化此过程,Swift为具有默认值的任何参数提供自动外部名称。自动外部名称与本地名称相同,就好像您在代码中的本地名称之前编写了哈希符号一样。

So your first function declaration

所以你的第一个函数声明

func DoIt(a: Int, b: Int, c : Int = 0) -> Int

is treated by the compiler as

被编译器视为

func DoIt(a: Int, b: Int, c c : Int = 0) -> Int

with an external parameter name "c" for the third parameter. This function would have to be called as

使用外部参数名称“c”表示第三个参数。必须将此函数称为

DoIt(4, 5, c: 6)   // result: 15

But the call

但电话

DoIt(4, 5, 6)

does not match the declaration of your first function, only that of the other function

与第一个函数的声明不匹配,只与其他函数的声明匹配

func DoIt(a: Int, b: Int, c :NSObject) -> Int

(and the third argument is automatically bridged to NSNumber, which is a subclass of NSObject). That's why you get the "unexpected" output.

(第三个参数自动桥接到NSNumber,它是NSObject的子类)。这就是你获得“意外”输出的原因。

If you change the declaration of the first function to

如果将第一个函数的声明更改为

func DoIt(a: Int, b: Int, _ c : Int = 0) -> Int

(where _ stands for "no external parameter name") then you will get the expected output:

(其中_代表“无外部参数名称”)然后您将获得预期的输出:

DoIt(4, 5, 6)   // result: 15

#1


4  

From "Functions" in the Swift documentation (emphasis added):

从Swift文档中的“函数”(重点添加):

External Names for Parameters with Default Values

具有默认值的参数的外部名称

In most cases, it is useful to provide (and therefore require) an external name for any parameter with a default value. This ensures that the argument for that parameter is clear in purpose if a value is provided when the function is called.

在大多数情况下,为任何具有默认值的参数提供(因此需要)外部名称是很有用的。这样可以确保在调用函数时提供值时,该参数的参数是有目的的。

To make this process easier, Swift provides an automatic external name for any parameter that has a default value. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code.

为了简化此过程,Swift为具有默认值的任何参数提供自动外部名称。自动外部名称与本地名称相同,就好像您在代码中的本地名称之前编写了哈希符号一样。

So your first function declaration

所以你的第一个函数声明

func DoIt(a: Int, b: Int, c : Int = 0) -> Int

is treated by the compiler as

被编译器视为

func DoIt(a: Int, b: Int, c c : Int = 0) -> Int

with an external parameter name "c" for the third parameter. This function would have to be called as

使用外部参数名称“c”表示第三个参数。必须将此函数称为

DoIt(4, 5, c: 6)   // result: 15

But the call

但电话

DoIt(4, 5, 6)

does not match the declaration of your first function, only that of the other function

与第一个函数的声明不匹配,只与其他函数的声明匹配

func DoIt(a: Int, b: Int, c :NSObject) -> Int

(and the third argument is automatically bridged to NSNumber, which is a subclass of NSObject). That's why you get the "unexpected" output.

(第三个参数自动桥接到NSNumber,它是NSObject的子类)。这就是你获得“意外”输出的原因。

If you change the declaration of the first function to

如果将第一个函数的声明更改为

func DoIt(a: Int, b: Int, _ c : Int = 0) -> Int

(where _ stands for "no external parameter name") then you will get the expected output:

(其中_代表“无外部参数名称”)然后您将获得预期的输出:

DoIt(4, 5, 6)   // result: 15