Навіщо мені потрібні підкреслення швидко?


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))

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

Відповіді:


353

Існує кілька нюансів для різних випадків використання, але загалом підкреслення означає "ігнорувати це".


При оголошенні нової функції підкреслення підказує Swift, що параметр не повинен мати мітки при виклику - саме так ви бачите. Більш повна декларація функції виглядає так:

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

"label" - це мітка аргументу, і вона повинна бути присутнім під час виклику функції. (А оскільки 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
}

Якщо ви зв'язуєте кортежі випадків у операторі перемикання, підкреслення може працювати як підстановка, як у цьому прикладі (скорочено від однієї у мові програмування 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 для типів та нижчогоCamelCase для всіх інших символів.

Префіксація або суфіксація назви символу з підкресленням - це конвенція стилю, яка історично використовується для розрізнення символів приватного / внутрішнього використання від експортованого API. Однак Swift має модифікатори доступу для цього, тому ця конвенція, як правило, розглядається як неідіоматична у Swift.

Кілька символів з подвійним підкресленням префіксів ( func __foo()) ховаються в глибині SDK Apple: Це символи (Obj) C, імпортовані в Swift за допомогою NS_REFINED_FOR_SWIFTатрибута. Apple використовує це, коли вони хочуть зробити "більш швидку" версію API (Obj) C - наприклад, щоб перетворити типово-агностичний метод у загальний метод . Їм потрібно використовувати імпортований API, щоб зробити вдосконалену версію Swift роботою, тому вони використовують для того, __щоб тримати її доступною, ховаючи її від більшості інструментів та документації.


@rickster, Яке значення підкреслення на початку такого методу, як цей-> 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 введення імен параметрів у викликах функцій стало обов'язковим - навіть для першого. Отже, оскільки це може спричинити величезну проблему з кодом, написаним у швидкій формі 2, ви можете використовувати підкреслення в декларації, щоб запобігти необхідності запису імені параметра під час виклику. Тож у цьому випадку він говорить "не хвилюйся назви зовнішнього параметра". Де зовнішнє ім'я параметра - це те, що ви називаєте параметри поза функцією (під час виклику), а не всередині. Ці зовнішні імена параметрів називаються мітками аргументів. http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some- iakots/ ... подивіться, як параметру даються два імені? перше, де йде підкреслення. Сподіваємось, це допомагає, і запитайте, чи все ще плутати.


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:)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.