let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)
Can anyone explain, what $0
and $1
means in swift?>
$0
and$1
are Closure’s first and second shorthand arguments (a.k.a.Shorthand Argument Names
orSAN
for short). The shorthand argument names are automatically provided by Swift. The first argument can be referenced by$0
, the second argument can be referenced by$1
, the third one by$2
, and so on.
As you know, a Closure is a self-contained block of functionality (a function without name) that can be passed around and used in your code. Closure has different names in other programming languages as well as slight differences in meaning – it's Lambda in Python and Kotlin or Block in C and Objective-C.
let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]
1. Normal Function
func backward(_ n1: String, _ n2: String) -> Bool {
return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)
/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */
2. Inline Closure Expression
reverseOrder = coffee.sorted(by: { (n1: String,
n2: String) -> Bool in return n1 > n2 } )
3. Inferring Type From Context
reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } )
4. Implicit Returns from Single-Expression Closures
reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } )
5. Shorthand Argument Names
reverseOrder = coffee.sorted(by: { $0 > $1 } )
/* $0 and $1 are closure’s first and second String arguments. */
6. Operator Methods
reverseOrder = coffee.sorted(by: >)
/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */
map
with dot notationlet companies = ["bmw", "kfc", "ibm", "htc"]
let uppercasedCompanies = companies.map { (item) -> String in item.uppercased() }
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
map
with dot notationlet uppercasedCompanies = companies.map { $0.uppercased() }
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
filter
with remainder operatorlet 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 */
$0
, $1
, $2
, $3
and $4
let factorial = { $0 * $1 * $2 * $3 * $4 } (1, 2, 3, 4, 5)
print(factorial)
/* RESULT: 5! = 120 */
In Swift 5.2 you can access parameters of every instance via key path expression:
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] */
Of course, you can alternatively use a familiar syntax:
Regular syntax – $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...")
}
}
Regular syntax, however, is as following:
let completionHandler: (Bool) -> Void = { sayTheTruth in
if sayTheTruth {
print("It is true, sister...")
}
}
Also, let's see how Kotlin's lambda is similar to Swift's closure:
Swift
let element: [String] = ["Argentum","Aurum","Platinum"]
let characterCount = element.map { $0.count }
print(characterCount)
/* RESULT: [8, 5, 8] */
Kotlin
Often Kotlin's lambda expression has only one parameter with implicit name: 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] */