Зачем мне подчеркивания в swift?

161

Здесь написано: «Примечание: _означает« меня не волнует это значение »», но, исходя из JavaScript, я не понимаю, что это значит.

Единственный способ получить эти функции для печати - использовать подчеркивание перед параметрами:

func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(7, 3))
print(divmod(5, 2))
print(divmod(12,4))

Без подчеркиваний я должен написать это так, чтобы избежать ошибок:

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(a: 7, b: 3))
print(divmod(a: 5, b: 2))
print(divmod(a: 12,b: 4))

Я не понимаю это использование подчеркивания. Когда, как и почему я использую эти подчеркивания?

Майкл Рэйдер
источник

Ответы:

354

Есть несколько нюансов для разных вариантов использования, но, как правило, подчеркивание означает «игнорировать это».


При объявлении новой функции подчеркивание говорит Swift, что у параметра не должно быть метки при вызове - это тот случай, который вы видите. Более полное объявление функции выглядит так:

func myFunc(label name: Int) // call it like myFunc(label: 3)

«метка» является меткой аргумента и должна присутствовать при вызове функции. (А после Swift 3 по умолчанию требуются метки для всех аргументов.) «Name» - это имя переменной для того аргумента, который вы используете внутри функции. Более короткая форма выглядит так:

func myFunc(name: Int) // call it like myFunc(name: 3)

Это ярлык, который позволяет использовать одно и то же слово как для метки внешнего аргумента, так и для имени внутреннего параметра. Это эквивалентно func myFunc(name name: Int).

Если вы хотите, чтобы ваша функция могла вызываться без меток параметров, используйте подчеркивание, _чтобы метка была ничем / игнорировалась. (В этом случае вы должны указать внутреннее имя, если хотите использовать этот параметр.)

func myFunc(_ name: Int) // call it like myFunc(3)

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

_ = someFunction()

Или, как в статье, на которую вы ссылаетесь, игнорировать один элемент возвращаемого кортежа:

let (x, _) = someFunctionThatReturnsXandY()

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

PHPhotoLibrary.performChanges( { /* some changes */ },
    completionHandler: { success, _ in // don't care about error
        if success { print("yay") }
    })

Аналогично, при объявлении функции, которая принимает протокол или переопределяет метод суперкласса, вы можете использовать _для имен параметров игнорирование параметров. Поскольку протокол / суперкласс может также определять, что параметр не имеет метки, вы можете даже получить два подчеркивания подряд.

class MyView: NSView {
    override func mouseDown(with _: NSEvent) {
        // don't care about event, do same thing for every mouse down
    }
    override func draw(_ _: NSRect) {
        // don't care about dirty rect, always redraw the whole view
    }
}

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

for _ in 1...20 { // or 0..<20
    // do something 20 times
}

Если вы связываете регистры кортежей в операторе switch, подчеркивание может работать как подстановочный знак, как в этом примере (сокращено от одного в языке программирования Swift ):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
default:
    print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}

Одна последняя вещь , которая не совсем связаны, но я включу так (как отмечено комментариев), кажется , не вести людей здесь: подчеркивание в качестве идентификатора - например var _foo, func do_the_thing(), struct Stuff_- значит ничего , в частности , к Swift, но имеет несколько применений среди программистов.

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

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

Несколько символов с префиксами с двойным подчеркиванием ( func __foo()) скрываются в глубинах SDK Apple: это символы (Obj) C, импортированные в Swift с использованием NS_REFINED_FOR_SWIFTатрибута. Apple использует это, когда они хотят сделать «более Swifty» версию (Obj) C API - например, чтобы сделать метод, независимый от типа, в универсальный метод . Им нужно использовать импортированный API, чтобы заставить улучшенную версию Swift работать, поэтому они используют ее, __чтобы держать ее доступной, скрывая ее от большинства инструментов и документации.

rickster
источник
@rickster, Какое значение подчеркивания в начале метода, как этот one-> func _copyContents (инициализация ptr: UnsafeMutableBufferPointer <Element>) -> (Iterator, UnsafeMutableBufferPointer <Element> .Index)} из протокола Sequence.
Dev Gr
@devgr: Совершенно не связано, поэтому я бы рекомендовал опубликовать отдельный вопрос.
Рикстер
Конечно, я опубликую отдельный вопрос.
Dev Gr
Спасибо за "ничего не назначать" за возврат функции. Это было то, что я искал.
Абсин
8

В дополнение к принятому ответу, один из случаев использования _, когда вам нужно написать длинное число в коде

Более читаемый номер

Это не просто для чтения человеком:

let x = 1000000000000

Вы можете добавить _число, чтобы сделать его более читабельным:

let x = 1_000_000_000_000
Мойтаба Хоссейни
источник
6

Начиная с Swift 3, указание имен параметров при вызове функций стало обязательным - даже для первого. Таким образом, поскольку это может вызвать огромные проблемы с кодом, написанным на swift 2, вы можете использовать подчеркивание в объявлении, чтобы избежать необходимости записывать имя параметра при вызове. Таким образом, в этом случае говорится: «не волнует имя внешнего параметра». Где имя внешнего параметра - это то, что вы называете параметрами вне функции (при вызове), а не внутри. Эти внешние имена параметров называются метками аргументов. http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some-allts/ ... посмотрите, как параметру присвоено два имени? Ну, во-первых, это то, где подчеркивание происходит. Надеюсь, это поможет, и спросите, если все еще в замешательстве.

Каспар Уайли
источник
4
func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

_Является заполнителем для названия параметра. В вашем примере вы вызываете их по-разному, во второй функции вам нужно написать имя параметра a: 1.

Соглашение об именах функций Swift есть funcName(param1:param2:), и _для создания имени функции требуется заполнитель.

Во имя, имя

divmod(_:_:)

В то время как второй

divmod(a:b:)
davidhu
источник