Что такое символ подчеркивания в Swift References?

144

В справочном разделе документации Apple есть много примеров такого рода вещей:

func runAction(_action: SKAction!)

Objective-C «эквивалент» этого:

- (void)runAction:(SKAction *)action

Меня поражает, что, вероятно, важно, чтобы (в справочнике по Swift) после подчеркивания был пробел, а «действие» было написано курсивом.

Но я не могу понять, что это пытается передать. Так что, возможно, вопрос в том ... есть ли ссылка на условные обозначения, используемые в ссылках?

- вот страница, на которую я ссылаюсь в этой ссылке на использование подчеркивания: https://developer.apple.com/documentation/spritekit/sknode#//apple_ref/occ/instm/SKNode/runAction

Обновить

Swift 3 внес некоторые изменения в то, как имена и параметры параметров функций / методов и метки аргументов используются и именуются. Это имеет последствия для этого вопроса и его ответа. @Rickster делает потрясающую работу, отвечая на другой вопрос о _underscores в функциях, которые проясняют большую часть этого вопроса, здесь: Зачем мне нужны подчеркивания в swift?

Смущенный
источник
3
С меткой [underscore.js] ??
Мартин Р
3
Документация соответствует математическому соглашению об использовании курсива для имен переменных. Например: sin² a + cos² a = 1.
rob mayoff

Ответы:

116

Оба ответа были правильными, но я хочу уточнить немного больше.

_используется для изменения поведения имени внешнего параметра для методов .

В разделе « Локальные и внешние имена параметров для методов » документации говорится:

Swift присваивает первому имени параметра в методе локальное имя параметра по умолчанию и по умолчанию дает второму и последующим именам параметров как локальные, так и внешние имена параметров.

С другой стороны, функции по умолчанию не имеют внешних имен параметров.

Например, у нас есть этот foo()метод, определенный в классе Bar:

class Bar{
    func foo(s1: String, s2: String) -> String {
        return s1 + s2;
    }
}

Когда вы звоните foo(), это называется как bar.foo("Hello", s2: "World").

Но вы можете переопределить это поведение, используя _перед тем, s2где оно объявлено.

func foo(s1: String, _ s2: String) -> String{
    return s1 + s2;
}

Затем, когда вы вызываете foo, он может быть просто назван как bar.foo("Hello", "World")без имени второго параметра.

Возвращаясь к вашему случаю, runActionэто метод, потому что он SKNode, очевидно , связан с типом . Таким образом, установка _параметра before actionпозволяет вам звонить runActionбез внешнего имени.

Обновление для Swift 2.0

Функция и метод теперь работают одинаково с точки зрения объявления имени локального и внешнего аргумента.

Функции теперь вызываются с использованием внешнего имени параметра по умолчанию, начиная со второго параметра. Это правило относится только к чистому коду Swift.

Таким образом, предоставляя _перед функцией функцию , вызывающая сторона не должна будет указывать имя внешнего параметра, так же, как вы делали бы для метода .

Аарон Хе
источник
9
Смущен, если _писать перед вторым параметром, ваш ответ достаточно однозначен; что если в func runAction(_action: SKAction!), _перед первым параметром стоит перед или если вы напишете следующий код, func foo(_ s1: String) { // your code }Xcode выдаст вам предупреждение, но есть много кода, как func bringSubviewToFront(_ view: UIView)в ссылке, почему?
Уилл Чжан
10
так что, по сути, он делает это без причины и просто смущает всех. здорово.
ботбот
2
Подчеркивание известно как «Джокер» Pattern developer.apple.com/library/ios/documentation/Swift/Conceptual/...
user2143356
@Wyatt Zhang, доктор говорит, что использование _первого параметра является посторонним. Я могу предположить, что дизайнеры считают, что этого достаточно для вашего кода и он не улучшает читабельность, а наоборот, это портит код. Итак, вы получите предупреждение. Ссылка имеет противоположную цель: она должна быть как можно более понятной - поэтому подчеркивание первого параметра упоминается для КАЖДОГО метода. Это все объяснило)
Дмитрий Грязин
4
Важно отметить, что Swift 3.0 меняет дело. Все ярлыки обязательны, если не указано иное. Таким образом, -первый параметр больше не является посторонним. Например: override func viewWillAppear(_ animated: Bool)сигнализирует о том, что вызывающая сторона (код Objective C) не будет использовать метку параметра
Мистер Т
85

Подчеркивание - это общий токен, используемый для обозначения отброшенного значения.

В данном конкретном случае это означает, что функция будет вызываться runAction(argument)вместоrunAction(action:argument)

В других контекстах оно имеет другое подобное значение, например:

for _ in 0..<5 { ... }

Это означает, что мы просто хотим выполнить блок 5 раз, и нам нет дела до индекса внутри блока.

В контексте:

let (result, _) = someFunctionThatReturnsATuple()

Это означает, что нас не волнует, что является вторым элементом кортежа, только первым.

Дэвид Берри
источник
Таким образом, в этом случае аргумент (действие) является опцией?
Смущенный
1
Нет, это приводит к тому, что имя внешнего параметра (action :) в этом случае будет пустым, поэтому пропускается. Аргумент все еще обязателен, он просто не помечен как action :.
Дэвид Берри
4
Реальный ответ - это сочетание ответа @ dasblinkenlight и моего. Он более конкретно рассматривает этот конкретный случай, а мой - более широкий вопрос, что означает _?
Дэвид Берри
4
Вы можете использовать знак сброса также для очень больших чисел, чтобы сделать их более читабельными, как этоlet pi = 3.141_592_653_59
SMP
занятно, вы также можете использовать его , чтобы сделать очень большие цифры менее читаемыми, какlet pi = 3.1_4_15_92___63
Дэвид Берри
15

Начиная с Swift 3 все метки аргументов являются обязательными по умолчанию .

Вы можете заставить IDE скрыть метку аргумента с помощью _.

func foo(a: String) {
}

func foo2(_ a: String) {
}

называется foo(a: "abc")иfoo2("abc")

Примечание. Это можно использовать только в том случае, если одновременно aуказана (внешняя) метка аргумента и (внутренняя) переменная . Это эквивалентно - func foo(a a: String)не примет _.

Почему Apple использует это?

Вы можете видеть, что Apple использует его через API. Библиотеки Apple по-прежнему написаны на Objective-C (если нет, они в любом случае имеют одни и те же имена функций, которые были разработаны для синтаксиса Objective-C)

Функции вроде applicationWillResignActive(_ application: UIApplication)бы имеют избыточное имя параметра application, поскольку в имени функции уже есть приложение .

Ваш пример

func runAction(_ action: SKAction!)будет называться без это _метки , как runAction(action:). Имя параметра actionбудет избыточным, так как оно уже есть в имени функции. Это цель и почему это там.

Якуб Трухларж
источник
13

Идентификатор перед объявлением параметра определяет имя внешнего параметра. Это имя, которое должно быть предоставлено вызывающей стороной при вызове функции:

func someFunction(externalParameterName localParameterName: Int)

Swift предоставляет автоматическое внешнее имя для любого заданного по умолчанию параметра, если вы сами не предоставляете внешнее имя. Использование подчеркивания для имени внешнего параметра исключает из этого поведения:

Вы можете отказаться от этого поведения, написав подчеркивание ( _) вместо явного внешнего имени при определении параметра.

Вы можете прочитать больше об этом поведении в разделе « Внешние имена для параметров со значениями по умолчанию» здесь .

dasblinkenlight
источник
так что ... дай мне посмотреть, поняла ли это моя глупость. В этом примере я должен назвать переменную / константу параметра как «действие» и назначить ее SKAction, который я хочу запустить этой функцией, и Swift автоматически присваивает требуемый параметр по умолчанию «действие». ОДНАКО, если я хочу произвольно назвать это действие, я должен использовать подчеркивание в вызове функции?
Смущенный
4
@ Confused Я понимаю, что SKдизайнеры не хотят, чтобы вы писали actionдважды, потому что «действие» уже является частью имени функции. Другими словами, они не хотят, чтобы вы писали sprite.runAction(action:moveGroundSpritesForever). Цель внешних имен параметров состояла в том, чтобы сделать ваш код «читаемым как предложение»; использование actionдважды приведет к поражению цели этого.
dasblinkenlight
Некоторые огни зажглись в темноте. Я думаю, я понял. Эта функция языка предназначена для того, чтобы вызывающие функции в Swift выглядели так же, как если бы вы вызывали метод с параметрами в Objective-C. Может быть.
Смущенный
1
Однако подчеркивание может быть использовано для того, чтобы как-то отказаться от использования этих внешних имен параметров для параметров, определенных значением по умолчанию ... просто еще не видел, как это делается, пока. Будет продолжать искать.
Смущенный
Итак ... короче говоря, он просто переключается между именованными параметрами и порядковыми параметрами, так что вы можете легко переключаться между foo.bar(param: 'fiddle') и foo.bar('fiddle') ПРИМЕЧАНИЕ: только с одним аргументом это действительно не становится очевидным ... но с несколькими аргументами это становится очень актуальным: foo.bar(param1: 'fiddle', param2: 'dee') vs foo.bar('fiddle','dee')
jrypkahauer
10

Я думаю, что это вызывает соглашение в Swift, которое делает его более близким к target-c, что лучше соответствует соглашениям по какао. В objc вы не (внешне) называете свой первый параметр. Вместо этого по соглашению вы обычно включаете внешнее имя в последнюю часть имени метода следующим образом:

- (void)myFancyMethodWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName;

[someInstance myFancyMethodWithFirstName:@"John" lastName:@"Doe"];

Чтобы сделать вызовы Swift API в соответствии с objc, вам нужно подавить имя внешнего параметра первого параметра.

func myFancyMethodWithFirstName(_ firstName:String, lastName:String);

someInstance.myFancyMethodWithFirstName("John", lastName:"Doe")
smileBot
источник
2
Мне нравится это объяснение. изучив Obj-C первым, вы все прояснили. Это также подчеркивает важность правильного присвоения имен методу в Swift, а именно, последняя часть имени метода должна описывать первый аргумент, как это обычно имеет место в Obj-C. хорошая вещь.
rrrrrraul
5

На самом деле, существует разница между реальным кодом, используемым для определения метода, и объявлением метода в документации Apple. Давайте UIControl «s - addTarget: Действие: forControlEvents: метод, например, реальный код: введите описание изображения здесь

Но в документах это выглядит так (обратите внимание _ перед целью): введите описание изображения здесь

В реальном коде _ используется, чтобы внешнее имя второго или последующего параметра не появлялось при вызове метода, тогда как в документах _ перед локальным именем параметра указывает, что при вызове метода или функции вы не должны предоставлять внешнее имя.

Нет внешнего имени, когда функция вызывается по умолчанию, если вы не предоставите свое собственное или не добавите # перед (без пробелов) локальным именем параметра, например, вот как мы используем dispatch_after : введите описание изображения здесь

И в документах это выглядит так (обратите внимание на три _): введите описание изображения здесь

Соглашение об объявлении функции точно такое же, как я описал для метода.

fujianjin6471
источник
1

Просто визуально.

введите описание изображения здесь

Как вы можете видеть, _просто make пропускает локальное имя параметра или нет.

Ник Ков
источник