为什么Swift也需要参数名称,但同时又需要参数名称呢?

时间:2019-10-11 17:50:56

标签: swift language-design named-parameters

在Swift中,当您调用函数时,必须标记参数,除非函数的作者明确允许您禁止这样做。就语言设计而言,这是否有原因?我一直认为参数标签是允许调用者以对参数有意义的任何方式对参数进行排序的一种好方法,但是这种感觉就像很多无意义/无用的样板。

示例:

如果我们这样定义函数makeDog:

makeDog(legs: int, name: String)->Dog{}

然后必须这样调用它:

makeDog(legs: 4, name: "fido")

不能 这样调用(编译器错误):

makeDog(name: "fido", legs: 4)

写后记:即使是命名参数的StackOverflow标签说明也说:

  

使用命名参数,您可以通过将参数与参数的名称而非参数在列表中的位置相关联,来为特定参数指定参数。

5 个答案:

答案 0 :(得分:1)

使用名称来澄清每个原因。

迅速地,参数可以是匿名的,您可以使用它们的订单号来使用它们。您通常会在闭包中看到它们,而在Swift中,函数就是闭包

所以顺序很重要,名称更明确。

想象一下sorted上的[Int]函数:

[1, 2].sorted(by: <#(Int, Int) throws -> Bool#>)

您怎么知道这两个参数中的哪一个应位于<运算符的右侧或左侧? 订购!

出于自我记录的代码的原因,您可以将它们命名为第一和第二,以防止在函数中丢失对其顺序的跟踪:

[1, 2].sorted { first, second -> Bool in
    return first < second
}

但是您可能知道,您可以摆脱名称,而只使用订单号:

[1, 2].sorted {
    return $0 < $1
}

您可能知道,这个<是Swift中的inem函数 ,如下所示:

func <(lhs: Int, rhs: Int)->Bool { return lhs < rhs }

因此您可以将其名称作为sorted的参数传递给整个函数:

[1, 2].sorted(by: <)

它的参数有名称,但是您使用了几次? 零!,那么当您通过时,编译器如何知道要使用哪一个?

功能签名!

参数的类型,它们的顺序以及函数的返回值的类型

答案 1 :(得分:1)

理解这一点的方法是认识到标签的目的不是 来告诉编译器这是哪个参数。顺序和类型,再加上默认值,就可以做到。

标签的目的纯粹是为了向主叫方规定主叫方必须说的话。

例如:

func f(p1 param1:String = "one", p2 param2:Int = 2) {}

f(p1:"hey", p2:42)
f(p1:"hey")
f(p2:42)
f()
// but not:
// f(p2:42, p1:"hey")

标签p1:并不表示“编译器,这是param1参数。”

这意味着,“调用方,如果您包含此参数(如果同时包含这两个参数,则必须先出现),则必须将其标记为p1:。”

答案 2 :(得分:0)

Swift这么做有两个原因。

一个是Objective-C对语言设计师的影响。命名参数是Objective-C语言(以及其他语言)的功能。

另一个原因是使用命名参数允许代码进行自我记录。

如果可以按任何顺序指定命名参数,就像您在其他语言中所做的那样,这将很有趣。

您可以在此处详细了解Swift功能的详细信息:Functions

答案 3 :(得分:0)

尚未提及的一件事是具有多个带有默认值的参数的函数或初始化程序,而您只想覆盖一个或两个默认值。例如:

func foo(aString: String = "", anInt: Int = 42, aFloat: Float = 10) {}

foo(aFloat: 50) // Skip the params where you want to use the defaults.

答案 4 :(得分:0)

正如其他答案中提到的,这是因为 Swift 努力成为一种自文档化语言,重点是呼叫站点的清晰度。

将外部/外部标签不作为参数的标识符,而是将标签视为帮助调用站点可能会有所帮助读起来像一个英语句子,清楚地解释了它的作用。

例如,考虑这个调用。

let result = multiply(value:20, by:1.5, thenBy:5)

现在看看它乱序。真是一团糟!

let result = multiply(thenBy:5, value:20, by:1.5)

那么标签是可选的呢...

let result = multiply(20, by:1.5)

当您对它们重新排序时,不太清楚您是将“20”乘以 1.5,因为可能是您将 self 乘以 1.5(即 self.multiply(by:)),然后有一些在没有上下文的情况下结尾的rando参数。同样,它不清楚。

let result = multiply(by:1.5, 20)

当然,你自然会回答'但那是一个可选的标签!当且仅当必须指定 all 标签时,顺序才无关紧要。但现在你把规则弄得乱七八糟,破坏了一致性,再一次,看我上面的第一个例子。

Swift 的一个重要原则是它试图保持一致/清晰高于一切。

正是上述对不一致的厌恶导致 Swift 在早期版本的 Swift 中引入了重大更改,即使您指定了第一个参数的标签也不需要。如果您愿意,它会隐式添加一个 _。但是为什么第一个参数要得到特殊处理呢?答案……不应该,他们在未来的版本中对其进行了更改,因为同样,一致性比聪明更重要,甚至超过引入破坏性更改。