Swift中何时需要参数标签?

时间:2014-07-18 00:59:52

标签: swift syntax

在回答this question时,调用init需要参数标签。这在Swift中是正常的。

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

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

然而,陌生人的力量正在发挥作用:

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

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

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

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

5 个答案:

答案 0 :(得分: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")

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

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

所有包括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")

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

func bar(one: Int, two: String){}
bar(1, "hello")

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

答案 1 :(得分:30)

Swift 3.0

在Swift 3.0中,slated to be released in late 2016,默认行为很简单:

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

您可以在Swift API Design Guidelines中最简洁地找到这些规则。最新行为是在SE-0056, "establish consistent label behavior across all parameters including first labels,"中提出的,并在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

覆盖默认行为

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

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

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

printAnimal(theAnimal: "Dog", legCount: 4)

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

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)

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

答案 2 :(得分:27)

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

func addChildViewController(_ childController: UIViewController)

这是proposed and approved Swift Evolution process的一部分,已在SR-961中实施。

答案 3 :(得分:8)

您可以在标签前使用#制作调用方法所需的参数标签。

E.g:

func addLocation(latitude : Double, longitude : Double) { /*...*/ }
addLocation(125.0, -34.1) // Not clear

可以这样改进:

func addLocation(#latitude : Double, #longitude : Double) { /*...*/ }
addLocation(latitude: 125.0, longitude: -34.1) // Better

(来自WWDC 2014 - 416 - Building Modern Frameworks,15分钟)

答案 4 :(得分:4)

只有使ObjC方法在Swift中看起来不错。

Documentation

  

实例方法

     

方法的本地和外部参数名称

     

具体来说,Swift在方法a local中提供第一个参数名称   参数名称默认情况下,并给出第二个和后续的   默认情况下,参数名称为本地和外部参数名称。   此约定与您的典型命名和调用约定相匹配   熟悉编写Objective-C方法,并为之做好准备   表达方法调用,无需限定参数   名。

     

...

     

上面描述的默认行为意味着Swift中的方法定义使用与Objective-C相同的语法风格编写,并以自然,富有表现力的方式调用。

     

自定义初始化

     

本地和外部参数名称

     

但是,初始值设定项在括号之前没有函数和方法的标识函数名称。因此,初始化程序参数的名称和类型在识别应该调用哪个初始化程序时起着特别重要的作用。因此,如果您不自己提供外部名称,Swift会为初始化程序中的每个参数提供自动外部名称

例如,这个ObjC类

@interface Counter : NSObject

@property int count;

- (void)incrementBy:(int)amount numberOfTimes:(int)numberOfTimes;

@end

并用Swift编写

class Counter {
    var count: Int = 0
    func incrementBy(amount: Int, numberOfTimes: Int) {
        count += amount * numberOfTimes
    }
}

调用ObjC版本

[counter incrementBy:10 numberOfTimes:2];

和Swift版

counter.incrementBy(10, numberOfTimes:2)

你可以看到它们几乎相同