Swift中何时需要参数标签?

jtb*_*des 63 syntax swift

在回答这个问题时,我们发现了一个调用标签是必需的init.这在Swift中是正常的.

class Foo {
    init(one: Int, two: String) { }
}

let foo = Foo(42, "Hello world") // Missing argument labels 'one:two:' in call
Run Code Online (Sandbox Code Playgroud)

然而,陌生人的力量在起作用:

extension Foo {
    func run(one: String, two: [Int]) { }
}

foo.run(one: "Goodbye", two: []) // Extraneous argument label 'one:' in call
Run Code Online (Sandbox Code Playgroud)

要在此处使用参数标签,必须明确声明.

我没有在文档中看到非常详尽的解释所有这些内容.哪些类/实例/全局函数是必需的参数标签?是否始终使用参数标签导出和导入Obj-C方法?

Con*_*nor 43

所有init方法都需要参数名称:

var view = NSView(frame: NSRect(x: 10, y: 10, width: 50, height: 50))
class Foo {
    init(one: Int, two: String) { }
}

let foo = Foo(one: 42, two: "Hello world")
Run Code Online (Sandbox Code Playgroud)

调用对象的所有方法都使用除第一个参数之外的所有参数名称:

extension Foo {
    func run(one: String, two: [Int]) { }
}
foo.run("Goodbye", two: [])
Run Code Online (Sandbox Code Playgroud)

所有包括Swift和objective-c中的类函数都遵循相同的模式.您还可以显式添加外部名称.

extension Foo{
class func baz(one: Int, two: String){}
class func other(exOne one: Int,  exTwo two: String){}
}
Foo.baz(10, two:"str")
Foo.other(exOne: 20, exTwo:"str")
Run Code Online (Sandbox Code Playgroud)

不是类函数的Swift函数不需要参数名称,但您仍然可以显式添加它们:

func bar(one: Int, two: String){}
bar(1, "hello")
Run Code Online (Sandbox Code Playgroud)

正如Bryan所说,当调用方法签名中具有参数名称的objective-c方法时,使Swift方法调用有意义.Init方法包括第一个参数,因为Swift将init方法从objective-c从initWith:...更改为Class(),因此第一个参数名称不再包含在方法名称中.

  • 来自Swift编程语言的有用引用:*"但是,初始化程序在它们的括号之前没有函数和方法的标识函数名称.因此,初始化程序参数的名称和类型在识别时起着特别重要的作用.应该调用哪个初始化程序.因此,如果你自己不提供外部名称,Swift会为初始化程序中的每个参数提供一个自动外部名称."* (2认同)

rav*_*ron 31

Swift 3.0

将于2016年底发布的 Swift 3.0中,默认行为很简单:

  • 默认情况下,所有方法的所有参数都有外部标签.

您可以在Swift API设计指南中最简洁地找到这些规则.这一最新行为在SE-0056中提出,"在包括第一标签在内的所有参数上建立一致的标签行为",并在SR-961中实施.可以在"覆盖默认行为"中按如下所述更改默认行为.

Swift 2.2

在Swift 2.2中,外部参数标签存在的语言默认值已经改变,现在变得更加简单.默认行为可以总结如下:

  • 方法和函数的第一个参数不应该有外部参数标签.
  • 方法和函数的其他参数应该有外部参数标签.
  • 初始值设定项的所有参数都应具有外部参数标签.

可以在"覆盖默认行为"中按如下所述更改默认行为.

一个例子

这些规则最好用一个例子来证明:

func printAnimal(animal: String, legCount: Int) {
    let legNoun = legCount == 1 ? "leg" : "legs"
    print("\(animal) has \(legCount) \(legNoun)")
}

struct Player {
    let name: String
    let lives: Int

    init(name: String, lives: Int) {
        self.name = name
        self.lives = lives
    }

    func printCurrentScore(currentScore: Int, highScore: Int) {
        print("\(name)'s score is \(currentScore). Their high score is \(highScore)")
    }
}


// SWIFT 3.0
// In Swift 3.0, all argument labels must be included
printAnimal(animal: "Dog", legCount: 4)
let p = Player(name: "Riley", lives: 3)
p.printCurrentScore(currentScore: 50, highScore: 110)

// SWIFT 2.2
// In Swift 2.2, argument labels must be included or omitted in exactly the following way
// given the definition of the various objects.
printAnimal("Dog", legCount: 4)
let p = Player(name: "Riley", lives: 3)
p.printCurrentScore(50, highScore: 110)

// In Swift 2.2, none of the following will work
printAnimal(animal: "Dog", legCount: 4)  // Extraneous argument label 'animal:' in call
let q = Player("Riley", lives: 3)  // Missing argument label 'name:' in call
p.printCurrentScore(50, 110)  // Missing argument label 'highScore:' in call
Run Code Online (Sandbox Code Playgroud)

覆盖默认行为

对于任何方法或函数的任何参数,您可能会偏离语言的默认值,但样式指南会正确地警告您不要这样做,除非有充分的理由.

要添加一个通常不存在的外部参数标签 - 仅适用于Swift 2.2,因为Swift 3.0默认为每个参数分配外部标签 - 或更改外部参数标签 - 适用于两个版本 - 写入所需的外部参数local参数标签前的标签:

func printAnimal(theAnimal animal: String, legCount: Int) {
    let legNoun = legCount == 1 ? "leg" : "legs"
    print("\(animal) has \(legCount) \(legNoun)")
}

printAnimal(theAnimal: "Dog", legCount: 4)
Run Code Online (Sandbox Code Playgroud)

要删除通常有外部参数标签的外部参数标签,请使用特殊的外部参数标签_:

func printAnimal(animal: String, _ legCount: Int) {
    let legNoun = legCount == 1 ? "leg" : "legs"
    print("\(animal) has \(legCount) \(legNoun)")
}

// SWIFT 3.0
printAnimal(theAnimal: "Dog", 4)

// SWIFT 2.2
printAnimal("Dog", 4)
Run Code Online (Sandbox Code Playgroud)

这些"默认覆盖"适用于任何方法或功能,包括初始化程序.

  • 那么,真正的原因只能来自实施这些指导方针的核心Swift团队.一些想法:这些规则使得如何将方法名称从Objective-C转换为Swift非常明显.此外,如果重要的话,它们比Swift 2.0及以下版本更复杂(以前,方法和功能的规则略有不同). (2认同)

Two*_*aws 29

从Swift 3.0开始,这又发生了变化:除非您明确选择使用外部名称,否则所有方法,函数和初始化程序都需要所有参数的参数标签_.这意味着像addChildViewController(_:)现在写的方法如下:

func addChildViewController(_ childController: UIViewController)
Run Code Online (Sandbox Code Playgroud)

这是作为Swift Evolution过程的一部分提出并批准的,并在SR-961中实施.

  • 我打算在这个问题上发布一个新问题,但也许你可以回答:为什么要省略一个参数标签?正如我所看到的那样,在不省略参数标签时,它似乎是随意的. (2认同)

Und*_*ndo 11

这是我通过阅读(相当稀疏的)文档并通过简单的实验来收集的内容:

哪个看起来好多了.当我在WWDC时,这被吹捧为Swift的一个特征:Java风格的现代,简短的论点,而不会牺牲可读性.正如Bryan Chen的回答所示,这也简化了从Objective-C的过渡.

  • 实际上,函数根本没有任何外部标签(默认情况下). (2认同)

Rob*_*ert 8

您可以#在标签之前使用调用方法所需的参数标签.

例如:

func addLocation(latitude : Double, longitude : Double) { /*...*/ }
addLocation(125.0, -34.1) // Not clear
Run Code Online (Sandbox Code Playgroud)

可以像这样改进:

func addLocation(#latitude : Double, #longitude : Double) { /*...*/ }
addLocation(latitude: 125.0, longitude: -34.1) // Better
Run Code Online (Sandbox Code Playgroud)

(来自WWDC 2014 - 416 - 建筑现代框架,15分钟)