Когда в Swift требуются метки аргументов?
при ответе на этот вопрос выяснилось, что метки аргументов были необходимы для вызова 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
чтобы использовать метку аргумента здесь, она должна быть объявлена явно.
Я не видел что-то очень подробное объяснение всего этого в документации. Для каких разновидностей класса/экземпляра/глобальных функций требуются метки аргументов? Are Obj-C методы всегда экспортируются и импортируются с метками аргументов?
6 ответов:
С Swift 3.0 это снова изменилось: все методы, функции и инициализаторы требуют меток аргументов для все параметры, если вы явно не отказались от использования внешнего имени
_. Это означает такие методы, какaddChildViewController(_:)теперь пишутся так:func addChildViewController(_ childController: UIViewController)Это предложен и утвержден в рамках быстрый процесс эволюции, и был реализован в SR-961.
все методы инициализации требуют имен параметров:
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")как Брайан сказал, что это делает быстрые вызовы методов разумными при вызове методов objective-c, которые имеют имена параметров в сигнатуре метода. Init методы включают в себя первый параметр, потому что стремительные изменения init методы с Objective-C от initWith:... В Class () поэтому имя первого параметра больше не включается в имя метода.
Swift 3.0
В Swift 3.0, планируется выпустить в конце 2016 года поведение по умолчанию-это просто:
- все параметры для всех методов имеют внешние метки по умолчанию.
вы можете найти эти правила наиболее кратко в Swift API Design Guidelines. Это новое поведение было предложено в 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переопределение поведения по умолчанию
для любого параметра любого метода или функции, вы можете отклонитесь от языка по умолчанию, хотя руководство по стилю справедливо предупреждает вас не делать этого, если нет веской причины.
чтобы добавить метку внешнего параметра, где обычно не было бы одного-только применимого в 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)To удалите метку внешнего параметра там, где она обычно есть, используйте специальную метку внешнего параметра
_: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)эти "переопределения по умолчанию" будут работать для любого метода или функции, включая инициализаторы.
вот что я смог собрать, прочитав (довольно скудную) документацию и проведя простые эксперименты:
Init методы всегда нужны их ярлыки. Методы Init, такие как метки, поскольку они дают понять, какой именно метод init вы хотите вызвать. В противном случае, это:
FooBar(foos: 5)и так:
FooBar(bars: 5)будет выглядеть точно так же:
FooBar(5)нигде это методы case-init являются единственным местом в Swift, где все они имеют одно и то же имя, но потенциально разные аргументы. Вот почему...
функции, методах и т. д. (Все, что не метод init) есть первая метка опущена - это для стиля и сократить скучную повторяемость. Вместо
aDictionary.removeValueForKey(key: "four")у нас есть это:
aDictionary.removeValueForKey("four")и все еще имеют довольно неоднозначные и легко читаемые аргументы для функций с два параметры. Так что вместо
anArray.insert("zebras", 9)у нас есть гораздо более понятная форма для чтения:
anArray.insert("zebras", atIndex: 9), который выглядит намного лучше. Когда я был на WWDC, это рекламировалось как особенность Swift: современные, короткие аргументы в стиле Java, не жертвуя удобочитаемостью. Это также облегчает переход от Objective-C, как ответ Брайана Чена показывает.
вы можете сделать метку параметра, необходимую для вызова метода с помощью
#перед подписью.например:
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 - создание современных механизмов, 15 минут)
это только сделать ObjC методы выглядит красиво в Swift.
Методы Экземпляра
локальные и внешние имена параметров для методов
в частности, Swift дает имя параметра в методе a местные имя параметра по умолчанию, и дает второй и последующие имена параметров как локальные, так и внешние по умолчанию. Этот соглашение соответствует типичному соглашению об именах и вызовах будет знаком с написанием методов 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 } }назвать язык версия
[counter incrementBy:10 numberOfTimes:2];и Swift версия
counter.incrementBy(10, numberOfTimes:2)вы можете видеть, что они почти одно и то же
Comments