【问题标题】:Why do I need underscores in swift?为什么我在swift中需要下划线?
【发布时间】:2017-01-30 07:50:48
【问题描述】:

Here 它说,“注意:_ 的意思是“我不关心那个值”,但是来自 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))

我不明白这种下划线的用法。我何时、如何以及为什么使用这些下划线?

【问题讨论】:

    标签: swift


    【解决方案1】:

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


    当声明一个新函数时,下划线告诉 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( { /* some changes */ },
        completionHandler: { success, _ in // don't care about error
            if success { print("yay") }
        })
    

    同样地,当声明一个采用协议或重写超类方法的函数时,可以使用_作为参数names来忽略参数。由于协议/超类也可能定义参数没有标签,因此您甚至可以以连续两个下划线结束。

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

    最后一件事不太相关,但我将包括在内,因为(如 cmets 所述)它似乎将人们引向这里:下划线 in 标识符 - 例如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 的“更 Swifty”版本时使用它——例如,to make a type-agnostic method into a generic method。他们需要使用导入的 API 来使精炼的 Swift 版本工作,因此他们使用 __ 来保持它可用,同时将其隐藏在大多数工具和文档中。

    【讨论】:

    • @rickster, 方法开头的下划线有什么意义,比如这个-> func _copyContents( initializing ptr: UnsafeMutableBufferPointer ) -> (Iterator,UnsafeMutableBufferPointer. Index) } 来自序列协议。
    • @devgr :完全不相关,所以我建议发布一个单独的问题。
    • 当然,我会发布一个单独的问题。
    • 感谢函数返回的“不要分配给任何东西”。这就是我要找的。​​span>
    【解决方案2】:

    除了接受的答案之外,_ 的用例之一是当你需要在代码中写一个长数字时

    更易读的数字

    ? 这不是一个易于人类阅读的内容:

    let x = 1000000000000
    

    ✅您可以在号码中添加_,使其更易于阅读:

    let x = 1_000_000_000_000
    

    带下划线的接口

    你可能会在 Swift 中遇到接口以_ 开头的地方。尽管它们在技术上声明为public,但以下划线开头视为此包的公共接口的一部分。我们可能会在任何版本中删除或更改它们,恕不另行通知,包括次要版本。

    例如@_exportedImport 或更多示例here in the official Swift Collections repo

    ⚠️ 干脆不要使用它们,或者您应该手动跟踪更改。

    【讨论】:

      【解决方案3】:

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

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

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

        在名字中,名字是

        divmod(_:_:)
        

        而第二个是

        divmod(a:b:)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-24
          • 2012-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多