不同的使用情况有一些微妙之处,但通常下划线的意思是“忽略这个”。
在声明一个新函数时,下划线告诉Swift在调用时该参数不应该有标签——这就是你所看到的情况。完整的函数声明如下:
func myFunc(label name: Int) // call it like myFunc(label: 3)
"label"是一个参数标签,当你调用函数时必须存在。(自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( { },
completionHandler: { success, _ in
if success { print("yay") }
})
同样地,当声明一个采用协议或重写超类方法的函数时,您可以使用
_
来忽略参数
名称。由于协议/超类可能还定义该参数没有标签,因此您甚至可能会得到两个连续的下划线。
class MyView: NSView {
override func mouseDown(with _: NSEvent) {
}
override func draw(_ _: NSRect) {
}
}
与前两种样式有些相关:当使用绑定本地变量/常量的流程控制结构时,您可以使用_
来忽略它。例如,如果您想迭代一个序列而不需要访问其成员:
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 _foo
,func do_the_thing()
,struct Stuff_
) 在 Swift 中没有特殊含义,但在程序员中有一些用途。
名称中的下划线是一种样式选择,但在 Swift 社区中并不受欢迎,因为 Swift 有关于类型使用 UpperCamelCase 和其他所有符号都使用 lowerCamelCase 的强烈约定。
在符号名称前缀或后缀上加下划线是一种样式约定,历史上被用来区分仅供内部使用的私有符号和导出的 API。然而,Swift 已经有了访问修饰符,因此这种约定通常在 Swift 中被视为非惯用语。
一些以双下划线前缀 (func __foo()
) 的符号隐藏在 Apple 的 SDK 深处:这些是通过 NS_REFINED_FOR_SWIFT
属性从 (Obj)C 导入到 Swift 中的符号。当他们想要将一个 "(Obj)C API" 转换为 "更像 Swift 的 API" 时,Apple 会使用这个方法。例如,将类型不明确的方法转换为通用方法。他们需要使用导入的 API 来使改进后的 Swift 版本工作,因此他们使用 __
来保持其可用性,同时又隐藏它以避免出现在大多数工具和文档中。