Swift References中的_下划线代表什么?


144

在Apple文档的参考部分中,有很多这类事情的实例:

func runAction(_action: SKAction!)

的Objective-C“等效”是:

- (void)runAction:(SKAction *)action

令我惊讶的是,(在Swift参考资料中)下划线和“动作”用斜体字后要留一个空格可能很重要。

但是我不知道这是要传达什么。所以也许问题是...参考文献中使用的约定是否有参考文献?

-这是我在此引用中指向下划线使用的页面:https : //developer.apple.com/documentation/spritekit/sknode#//apple_ref/occ/instm/SKNode/runAction

更新资料

Swift 3对如何使用和命名函数/方法参数名称和参数标签进行了一些更改。这对这个问题及其答案有影响。@Rickster在回答有关_underscores函数的另一个问题方面做得非常出色,可以解决此问题,这里:为什么我需要迅速使用下划线?


3
标记[underscore.js]?
Martin R

3
该文档遵循使用斜体表示变量名的数学惯例。例如:sin² 一个 +cos² 一个 = 1。
抢劫mayoff

Answers:


116

两种答案都是正确的,但我想澄清一点。

_用于修改方法的外部参数名称行为

在文档的“ 方法的本地和外部参数名称”部分中,它表示:

Swift 默认为方法中的第一个参数名称提供一个本地参数名称,默认情况下为第二个及后续参数名称提供本地和外部参数名称

另一方面,默认情况下,函数没有外部参数名称。

例如,我们foo()在类中定义了此方法Bar

class Bar{
    func foo(s1: String, s2: String) -> String {
        return s1 + s2;
    }
}

当您打电话时foo(),它称为bar.foo("Hello", s2: "World")

但是,您可以通过_s2声明的位置前面使用来覆盖此行为。

func foo(s1: String, _ s2: String) -> String{
    return s1 + s2;
}

然后,当您调用时foo,可以像bar.foo("Hello", "World")没有第二个参数的名称一样简单地调用它。

回到您的情况,这runAction是一种方法,因为它SKNode显然与type相关联。因此,放置一个_before参数action可以使您runAction无需外部名称即可进行调用。

Swift 2.0更新

现在,函数和方法在局部和外部参数名称声明方面的工作方式相同

现在,默认情况下通过使用外部参数名称(从第二个参数开始)来调用函数。该规则仅适用于纯Swift代码。

因此,通过_函数前面提供,调用者将不必指定外部参数名称,就像您对method所做的一样。


9
感到困惑的是,如果在_第二个参数之前写入,您的答案就足够了;如果in中的func runAction(_action: SKAction!)_在第一个参数之前,或者如果您编写以下代码 ,该怎么办?func foo(_ s1: String) { // your code }Xcode会警告您,但是func bringSubviewToFront(_ view: UIView)在引用中有很多代码,为什么?
张张

10
所以基本上,它无缘无故地这样做,只会使所有人感到困惑。太棒了
botbot


博士说,@ Wyatt Zhang说_第一个参数的用法是多余的。我可以做出一个假设,即设计师认为对于您的代码而言这显然足够了,并且不提高可读性,相反,这会弄脏代码。因此,您会收到警告。该引用的目的相反:必须尽可能清楚-因此,每个方法都提到了第一个参数的下划线。那会解释一切)
德米特里·格里亚津

4
请务必注意,Swift 3.0会改变一切。除非另有说明,否则所有标签都是必需的。因此,-第一个参数之前的no不再是多余的。例如:override func viewWillAppear(_ animated: Bool)发出信号,表明调用者(Objective-C代码)将不使用参数标签
T. Mr.

85

下划线是用于指示丢弃值的通用标记。

在这种特定情况下,这意味着将调用函数runAction(argument)而不是runAction(action:argument)

在其他上下文中,它具有其他相似的含义,例如:

for _ in 0..<5 { ... }

这意味着我们只想执行5次该块,而不必关心该块中的索引。

在这种情况下:

let (result, _) = someFunctionThatReturnsATuple()

这意味着我们不在乎元组的第二个元素是什么,只有第一个。


那么在这种情况下,参数(一个动作)是一个选择吗?
2014年

1
不,在这种情况下,它将导致外部参数名称(action :)为空,因此将其省略。该参数仍然是必需的,只是没有用action:标记。
David Berry 2014年

4
真正的答案是@dasblinkenlight的答案和我的答案的结合。他更精确地解决了这个具体问题,而我的解决了更广泛的问题,_是什么意思?
David Berry 2014年

4
您也可以对非常大的数字使用丢弃符号,以使其更具可读性let pi = 3.141_592_653_59
SMP 2014年

有趣的是,您还可以使用它来使非常大的数字难以理解,例如let pi = 3.1_4_15_92___63
David Berry

15

从Swift 3开始默认情况下所有参数标签都是必需的。

您可以使用强制IDE隐藏参数标签_

func foo(a: String) {
}

func foo2(_ a: String) {
}

foo(a: "abc")foo2("abc")

注意:这只能当使用a的是(外)参数标签(内部)变量名在同一时间。等价- func foo(a a: String)不会接受_

苹果为什么要使用它?

您可以看到Apple正在整个API中使用它。Apple的库仍是用Objective-C编写的(如果不是,它们仍然共享相同的函数名,这些函数名是为Objective-C语法设计的)

applicationWillResignActive(_ application: UIApplication)这样的函数将具有多余的参数名application,因为函数名中已经包含应用程序

你的例子

func runAction(_ action: SKAction!)将被称为没有它的_标志一样runAction(action:)。参数名称action将是多余的,因为函数名称中已经存在一个。那就是目的,为什么它在那里。


13

参数声明前面的标识符定义了外部参数名称。这是调用函数时调用者必须提供的名称:

func someFunction(externalParameterName localParameterName: Int)

如果您自己未提供外部名称,则Swift会为您定义的任何默认参数提供一个自动外部名称。使用下划线表示外部参数名称会退出此行为:

_定义参数时,可以通过写下划线()而不是显式的外部名称来选择退出此行为。

您可以在此处使用默认值的参数的外部名称 部分中了解有关此行为的更多信息。


所以...让我看看我的昏昏欲睡是否正确。在此示例中,我应该将参数变量/常量命名为“ action”,并将其分配给我要通过此函数运行的SKAction,然后Swift会自动将所需的默认参数命名为“ action”。但是,如果要自定义此操作的名称,则必须在函数调用中使用下划线?
2014年

4
@Confused我的理解是SK'设计师不希望您写action两次,因为“ action”已经是函数名称的一部分。换句话说,他们不希望您写信sprite.runAction(action:moveGroundSpritesForever)。外部参数名称的目的是使您的代码“读起来像句子”;使用action两次将无法达到目的。
dasblinkenlight 2014年

黑暗中有些灯亮着。我想我明白了。这种语言的功能旨在使Swift中的调用函数看起来很像在Objective-C中调用带有参数的方法。也许。
2014年

1
但是,可以使用下划线以某种方式选择不使用默认值定义的参数来使用这些外部参数名称...尚未看到如何完成。将继续寻找。
2014年

所以......总之,它简单地命名参数和序参数之间切换,让您轻松切换之间 foo.bar(param: 'fiddle') ,并 foo.bar('fiddle') 注意:只有一个说法果然不显而易见的......但多个参数就变得非常重要: foo.bar(param1: 'fiddle', param2: 'dee') VS foo.bar('fiddle','dee')
jrypkahauer

10

我认为这迫使Swift中采用一种约定,使其更接近Objective-C,从而更好地匹配了可可约定。在objc中,您不会(从外部)命名第一个参数。相反,按照惯例,您通常在方法名称的后半部分中包含外部名称,如下所示:

- (void)myFancyMethodWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName;

[someInstance myFancyMethodWithFirstName:@"John" lastName:@"Doe"];

为了使Swift api调用与objc一致,您将需要隐藏第一个参数的外部参数名称。

func myFancyMethodWithFirstName(_ firstName:String, lastName:String);

someInstance.myFancyMethodWithFirstName("John", lastName:"Doe")

2
我喜欢这个解释。首先了解了Obj-C,您已经清理了一切。它还强调了在Swift中适当命名Method的重要性,即Method名称的后半部分应描述第一个参数,这与Obj-C中的典型情况相同。好东西。
rrrrrraul

5

实际上,用于定义方法的实际代码与Apple文档中的方法声明之间存在差异。让我们以UIControl-addTarget:action:forControlEvents:方法为例,实际代码为: 在此处输入图片说明

但是在文档中,它看起来像这样(在目标之前请注意_): 在此处输入图片说明

在实际代码中,_用于使第二个或后续参数的外部名称在调用方法时不出现,而在docs中,_在参数的本地名称之前表示当您调用方法或函数时,不应提供一个外部名称。

默认情况下,调用函数时没有外部名称,除非您提供自己的名称或在参数的本地名称之前(不带空格)添加#,例如,这就是我们使用dispatch_after的方式在此处输入图片说明

在文档中,它看起来像这样(注意三个_): 在此处输入图片说明

函数声明的约定与我为方法描述的约定相同。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.