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

123

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

func runAction(_ action : SKAction!)

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

- (void)runAction:(SKAction *) action

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

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

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

Update

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

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

7 ответов

100
Лучший ответ

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

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

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

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, очевидно. Таким образом, добавление параметра _ до параметра action позволяет вызывать runAction без внешнего имени.

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

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

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

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

  • 9
    Смущен, если _ напишите перед вторым параметром, ваш ответ достаточно ясен; что если в func runAction(_action: SKAction!) , _ стоит перед первым параметром или если вы напишите следующий код, то func foo(_ s1: String) { // your code } Xcode выдаст вам предупреждение, но есть много кода, как func bringSubviewToFront(_ view: UIView) в ссылке, почему?
  • 8
    так что, по сути, он делает это без причины и просто смущает всех. классно.
Показать ещё 3 комментария
84

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

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

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

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

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

В этом контексте:

let (result, _) = someFunctionThatReturnsATuple()

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

  • 0
    Таким образом, в этом случае аргумент (действие) является опцией?
  • 1
    Нет, это приводит к тому, что имя внешнего параметра (action :) в этом случае будет пустым, поэтому опускается. Аргумент все еще требуется, он просто не помечен как action :.
Показать ещё 3 комментария
12

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

func someFunction(externalParameterName localParameterName: Int)

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

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

Подробнее об этом поведении читайте в разделе "Внешние имена для параметров со значениями по умолчанию здесь.

  • 0
    так что ... дай мне посмотреть, поняла ли это моя глупость. В этом примере я должен назвать переменную / константу параметра как «действие» и назначить ее SKAction, который я хочу запустить этой функцией, и Swift автоматически присваивает требуемый параметр по умолчанию «действие». ОДНАКО, если я хочу произвольно назвать это действие, я должен использовать подчеркивание при вызове функции?
  • 4
    @ Confused Я понимаю, что дизайнеры SK не хотят, чтобы вы дважды писали action , потому что «action» уже является частью имени функции. Другими словами, они не хотят, чтобы вы писали sprite.runAction(action:moveGroundSpritesForever) . Цель внешних имен параметров состояла в том, чтобы сделать ваш код «читаемым как предложение»; использование action дважды нанесло бы ущерб цели этого.
Показать ещё 3 комментария
7

Так как 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 будет избыточным, поскольку в имени функции уже есть один. Это цель и почему она там.

6

Я думаю, что это принуждает соглашение в Swift, что делает его ближе к objective-c, что лучше соответствует соглашениям cocoa. В 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")
  • 2
    Мне нравится это объяснение. изучив Obj-C первым, вы все прояснили. Это также подчеркивает важность правильного присвоения имен методу в Swift, а именно, последняя часть имени метода должна описывать первый аргумент, как это обычно происходит в Obj-C. хорошая вещь.
4

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

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

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

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

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

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

0

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

Изображение 1919

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню