Що означає $ 0 та $ 1 у швидкому закритті?


77
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)

Хто-небудь може пояснити, що $0і що $1означає швидко?

Більше зразка

array.forEach {
    actions.append($0)
}

Відповіді:


119

$0- це перший параметр, який передається в закриття. $1це другий параметр і т. д. Це закриття, яке ви показали, є скороченням для:

let sortedNumbers = numbers.sort { (firstObject, secondObject) in 
    return firstObject > secondObject
}

Чи можу я написати свою власну логіку в закритті, використовуючи перший параметр і другий?
aashish tamsya

4
Так, це вся мета закриття.
AdamPro13

2
спасибі товаришу, ваша відповідь допомогла мені зрозуміти кращу частину закриття
aashish tamsya

43

TL; DR

Свіфт 5.3

$0і $1є першим і другим скорочувальними аргументами Закриття (він же Shorthand Argument Namesабо SANскорочено). Імена скорочених аргументів автоматично надаються Swift. На перший аргумент можна посилатись $0, на другий аргумент можна посилатися $1, на третій - $2тощо.

Як ви знаєте, Закриття - це самостійний блок функціональних можливостей (функція без імені), який можна передавати та використовувати у коді. Закриття має різні назви в інших мовах програмування, а також незначні відмінності у значенні - це Лямбда на Python та Kotlin або Блок на C та Objective-C .


Скорочення закриття

let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]

1. Нормальна функція

func backward(_ n1: String, _ n2: String) -> Bool {
    return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)


/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */

2. Вбудований вираз закриття

reverseOrder = coffee.sorted(by: { (n1: String, 
                                    n2: String) -> Bool in return n1 > n2 } )

3. Висновок типу з контексту

reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } )

4. Неявна повернення із закритих виразів

reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } )

5. Стенографічні назви аргументів

reverseOrder = coffee.sorted(by: { $0 > $1 } )

/* $0 and $1 are closure’s first and second String arguments. */

6. Методи оператора

reverseOrder = coffee.sorted(by: >)

/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */


Функція вищого порядку mapз крапковим позначенням

let companies = ["bmw", "kfc", "ibm", "htc"]

let uppercasedCompanies = companies.map { (item) -> String in item.uppercased() }

/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */

SAN у mapформаті HOF із крапковим позначенням

let uppercasedCompanies = companies.map { $0.uppercased() }

/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */


SAN у HOF filterз оператором залишку

let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let filteredNumbers = numbers.filter { ($0 % 2) == 0 }

print(filteredNumbers)

/* RESULT: [2, 4, 6, 8, 10] */


Повторення $0

let cubedNumber = { $0 * $0 * $0 } (25)

print(cubedNumber)

/* RESULT:  25^3 = 15625 */


Три Скорочений Аргумент імена - $0, $1,$2

let math: (Int8, Int8, Int8) -> Int8 = { $0 + $1 - $2 }

func feedClosure() -> (Int8, Int8, Int8) -> Int8 {
    return math
}
feedClosure()(10, 20, 100)

/* RESULT:  (10 + 20 - 100) = -70 */


П'ять SANs - $0, $1, $2, $3і$4

let factorial = { $0 * $1 * $2 * $3 * $4 } (1, 2, 3, 4, 5)

print(factorial)

/* RESULT:  5! = 120 */


Вираз ключового шляху

У Swift 5.2 ви можете отримати доступ до параметрів кожного екземпляра за допомогою виразу шляху шляху:

struct Lighter {
    let manufacturer: String
    let refillable: Bool
}

let zippo = Lighter(manufacturer: "Zippo", refillable: true)
let cricket = Lighter(manufacturer: "Cricket", refillable: false)

let lighters: [Lighter] = [zippo, cricket]

let refillableOnes = lighters.map(\.refillable)

print(refillableOnes)

/* RESULT:  [true, false] */

Звичайно, ви можете використати знайомий синтаксис:

Регулярний синтаксис -$0.property :

let refillableOnes = lighters.map { $0.refillable }

print(refillableOnes)

/* RESULT:  [true, false] */


Скорочене ім'я аргументу з нижчим індексом

let arrays: [[String]] = [["Hello", "Hola"], ["world", "mundo"]]

let helloWorld = arrays.compactMap { $0[0] }

print(helloWorld)

/* RESULT:  ["Hello", "world"] */


Назва скороченого аргументу в обробнику завершення

let completionHandler: (Bool) -> Void = {
    if $0 {
        print("It is true, sister...")
    }
}

Однак регулярний синтаксис такий:

let completionHandler: (Bool) -> Void = { sayTheTruth in
    if sayTheTruth {
        print("It is true, sister...")
    }
}


Свіфт проти Котліна проти Пітона

Крім того, давайте подивимось, як лямбда Котліна схожа на закриття Свіфта:

Стрімкий

let element: [String] = ["Argentum","Aurum","Platinum"]

let characterCount = element.map { $0.count }

print(characterCount)

/* RESULT:  [8, 5, 8] */ 

Котлін

Часто лямбда - вираз Котлин має тільки один параметр з ім'ям неявного:it .

val element = listOf("Argentum","Aurum","Platinum")

val characterCount = element.map { it.length }

println(characterCount)

/* RESULT:  [8, 5, 8] */ 

But in Python there's no equivalent of Shorthand Argument Name.

Python

element = ["Argentum","Aurum","Platinum"]

characterCount = list(map(lambda x: len(x), element))

print(characterCount)

/* RESULT:  [8, 5, 8] */

Ваш приклад Python без потреби використовує лямбду. list(map(len, ....))вистачило б. Особисто я б використовував хіба що в критичному розділі продуктивності, [len(v) for v in ...]оскільки він чистіший і читабельніший.
Мартін Пітерс

1
Будь ласка, додайте швидку документацію Посилання
AsifHabib

Привіт @AsifHabib! Яке посилання на документи ви маєте на увазі - офіційні документи розробників чи будь-яке інше?
Енді Федоров,

1
@AndyFedoroff Офіційна документація
AsifHabib


33

Він представляє скорочені аргументи, надіслані в закриття, цей приклад розбиває його:

Свіфт 4:

var add = { (arg1: Int, arg2: Int) -> Int in
    return arg1 + arg2
}
add = { (arg1, arg2) -> Int in
    return arg1 + arg2
}
add = { arg1, arg2 in
    arg1 + arg2
}
add = {
    $0 + $1
}

let result = add(20, 20) // 40

6
Оскільки оператор додавання має той самий підпис функції, що і це закриття, ви можете розбити його ще більше, щоб просто:add = (+)
Самах

Він повинен чітко вказати тип із var add:((Int, Int) -> Int) = ...випадками 3 та 4, у моєму швидкому тесті 5.
Ітачі,

6

Посилання на перший та другий аргументи сортування. Тут sortпорівнюються 2 елементи та їх порядок. Ви можете переглянути офіційну документацію Swift для отримання додаткової інформації:

Swift автоматично надає скорочені імена аргументів для вбудованих закриттів, які можуть використовуватися для посилання на значення аргументів закриття за іменами $ 0, $ 1, $ 2 тощо.


3

Окрім відповіді @ Bobby, я хотів би додати приклад

var add: (Int,Int,Int)->Int
add = {
//So here the $0 is first argument $1 is second argument $3 is third argument
    return $0 + $1 + $2
//The above statement can also be written as $0 + $1 + $2 i.e is return is optional
}

let result = add(20, 30, 40) 
print(result) // Prints 90

це не може розглядатися як відповідь. Якщо ви хочете додати приклад, просто відредагуйте відповідь @
bobby

2

Це скорочені назви аргументів.

Swift автоматично надає скорочені імена аргументів для вбудованих закриттів, які можуть використовуватися для посилання на значення аргументів закриття за іменами $ 0, $ 1, $ 2 тощо.

Якщо ви використовуєте ці скорочені імена аргументів у своєму виразі закриття, ви можете опустити список аргументів закриття з його визначення, а кількість та тип імен скорочених аргументів будуть виведені з очікуваного типу функції. Ключове слово in також можна пропустити, оскільки вираз закриття складається повністю з його тіла:

    reversed = names.sort( { $0 > $1 } )

Тут $ 0 та $ 1 відносяться до першого та другого аргументів рядка закриття.

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