为什么我需要快速下划线?


161

在这里,它说,“注:_意思是‘我不关心这个值’”,但是从JavaScript来了,我不明白是什么意思。

我可以打印这些功能的唯一方法是在参数前使用下划线:

func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(7, 3))
print(divmod(5, 2))
print(divmod(12,4))

没有下划线,我必须这样写,以避免出现任何错误:

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(a: 7, b: 3))
print(divmod(a: 5, b: 2))
print(divmod(a: 12,b: 4))

我不理解此下划线用法。我何时,如何以及为什么使用这些下划线?

Answers:


353

不同的用例有一些细微差别,但是通常下划线表示“忽略此”。


当声明一个新函数时,下划线告诉Swift调用时该参数应该没有标签-就是这种情况。完整的函数声明如下所示:

func myFunc(label name: Int) // call it like myFunc(label: 3)

“标签”是参数标签,在调用函数时必须存在。(并且从Swift 3开始,默认情况下所有参数都需要标签。)“ name”是您在函数内部使用的该参数的变量名称。较短的形式如下:

func myFunc(name: Int) // call it like myFunc(name: 3)

这是一个快捷方式,可让您为外部参数标签和内部参数名称使用相同的词。等同于func myFunc(name name: Int)

如果希望不带参数标签就可以调用函数,请使用下划线_使标签为空/忽略。(在这种情况下,如果要使用该参数,则必须提供一个内部名称。)

func myFunc(_ name: Int) // call it like myFunc(3)

在赋值语句中,下划线表示“请勿分配任何内容”。如果要调用一个返回结果但不关心返回值的函数,则可以使用此方法。

_ = someFunction()

或者,就像您链接的文章中一样,忽略返回的元组的一个元素:

let (x, _) = someFunctionThatReturnsXandY()

当编写实现某些已定义函数类型的闭包时,可以使用下划线忽略某些参数。

PHPhotoLibrary.performChanges( { /* some changes */ },
    completionHandler: { success, _ in // don't care about error
        if success { print("yay") }
    })

同样,在声明采用协议或覆盖超类方法的函数时,可以使用_参数忽略参数。由于协议/超类也可能定义该参数没有标签,因此您甚至可以连续两个下划线结尾。

class MyView: NSView {
    override func mouseDown(with _: NSEvent) {
        // don't care about event, do same thing for every mouse down
    }
    override func draw(_ _: NSRect) {
        // don't care about dirty rect, always redraw the whole view
    }
}

与后两种样式有些相关:当使用绑定局部变量/常量的流控制构造时,可以使用_忽略它。例如,如果要迭代序列而不需要访问其成员,请执行以下操作:

for _ in 1...20 { // or 0..<20
    // do something 20 times
}

如果在switch语句中绑定元组用例,则下划线可以用作通配符,如本例所示(与The Swift Programming Language缩写相比):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
default:
    print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}

这似乎不太相关的最后一两件事,但我会因为包括(通过评论指出的),似乎在这里带领人们:下划线标识符-例如var _foofunc do_the_thing()struct Stuff_-手段没有什么特别的斯威夫特,但有几个用途在程序员之间。

名称中的下划线是样式的选择,但是在Swift社区中并不是首选,Swift社区对于将UpperCamelCase用于类型并将lowerCamelCase用于所有其他符号具有严格的约定。

使用下划线在符号名称前添加前缀或后缀是一种样式约定,以前一直用于区分私有/仅供内部使用的符号与导出的API。但是,Swift为此具有访问修饰符,因此该约定通常在Swift中被视为非惯用语。

func __foo()在Apple SDK的深度中,一些带有双下划线前缀()的符号潜伏着:这些是使用NS_REFINED_FOR_SWIFT属性导入到Swift的(Obj)C符号。Apple想要制作(Obj)C API的“更快速”版本时使用Apple,例如,将与类型无关的方法转换为通用方法。他们需要使用导入的API来使精致的Swift版本起作用,因此他们使用__使其保持可用状态,同时将其隐藏在大多数工具和文档中。


@rickster,下划线在方法开始时有什么意义,例如:-> func _copyContents(初始化ptr:UnsafeMutableBufferPointer <Element>)->(Sequence协议中的Iterator,UnsafeMutableBufferPointer <Element> .Index)}。
dev gr

@devgr:完全不相关,所以我建议您发布一个单独的问题。
里克斯特

当然,我将发布一个单独的问题。
dev gr

感谢“不要给任何东西”函数返回。这就是我想要的。
苦艾酒

8

除了可接受的答案外,的一种用例_是当您需要在代码中编写大量数字时

更具可读性的号码

这是不容易理解的:

let x = 1000000000000

您可以添加_数字以使其更易读:

let x = 1_000_000_000_000

6

从Swift 3开始,在函数调用上指定参数名称已成为强制性-甚至是第一次。因此,由于这可能会对swift 2中编写的代码造成巨大问题,因此可以在声明中使用下划线,以防止在调用时必须写入参数名称。因此,在这种情况下,就是说“不在乎外部参数名称”。外部参数名称是您在函数外部(调用时)而不是内部调用的参数。这些外部参数名称称为参数标签。http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some-thoughts/ ...看到参数是如何给两个名字的?好首先是下划线的去向。希望这会有所帮助,并询问是否仍然感到困惑。


4
func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

_是参数名称的占位符。在您的示例中,您以不同的方式调用它们,在第二个函数中,您需要编写参数name a: 1

Swift的函数名称约定为funcName(param1:param2:),它需要_作为占位符来创建函数的名称。

在名字里,名字是

divmod(_:_:)

而第二个是

divmod(a:b:)
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.