let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)
Can anyone explain, what $0 and $1 means in swift?
More Sample
array.forEach {
actions.append($0)
}
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)
Can anyone explain, what $0 and $1 means in swift?
More Sample
array.forEach {
actions.append($0)
}
TL;DR
$0 and $1 are closure’s first and second Shorthand Argument Names (SAN for short) or implicit parameter names, if you like. The shorthand argument names are automatically provided by Swift. The first argument is referenced by $0, the second argument is 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 it's Block in C and Objective-C.
let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]
1. Regular 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 {
(n1: String, n2: String) -> Bool in return n1 > n2
}
3. Inferring Type from context in a closure with an implicit return
reverseOrder = coffee.sorted { n1, n2 in n1 > n2 }
4. Shorthand Argument Names
reverseOrder = coffee.sorted { $0 > $1 }
/* $0 and $1 are closure’s first and second String arguments. */
5. Operator methods
reverseOrder = coffee.sorted(by: >)
/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */
let companies = ["bmw", "kfc", "ibm", "htc"]
let uppercased = companies.map {
(item: String) -> String in return item.uppercased()
}
print(uppercased)
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
let uppercased = companies.map { $0.uppercased() }
print(uppercased)
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let filteredNumbers = numbers.filter {
(arg: Int) -> Bool in return (arg % 2) == 0
}
print(filteredNumbers)
/* RESULT: [2, 4, 6, 8, 10] */
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] */
Variadic functions are ones that accept any number of parameters. One of the most famous variadic methods is print(...). Shorthand Argument Names are perfect for variadic functions.
fileprivate func dessert(_ fruits: String...) -> Bool {
return fruits.contains { $0 == "Apple" }
}
let contains = dessert("Mango", "Durian", "Papaya")
print(contains)
/* RESULT: false */
Here, allSatisfy() method indicates whether every element of a sequence satisfies a given predicate or not. The Any type represents values of any type. Existential any type is used for storing an any kind of value which conforms to a specific protocol. Also, I used here a shorthand syntax for optional binding (shadowing an existing constant).
let inputData: [Any]? = [1, 2, 3, "Hello"]
func satisfiesOrNot(_ inputData: any Sequence) -> Bool {
inputData.allSatisfy { $0 is Int }
}
if let inputData {
satisfiesOrNot(inputData)
}
/* RESULT: false */
let cubedNumber = { $0 * $0 * $0 } (25)
print(cubedNumber)
/* RESULT: 25^3 = 15625 */
If you use external values inside a closure, Swift captures them.
func trainer(_ said: String) -> (String) -> String {
return {
return "¡\(said) \($0)!"
}
}
let announcement = trainer("Bienvenido a mis cursos")
announcement("RealityKit 2022")
/* RESULT: "¡Bienvenido a mis cursos RealityKit 2022!" */
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 */
let factorial = { $0 * $1 * $2 * $3 * $4 } (1, 2, 3, 4, 5)
print(factorial)
/* RESULT: 5! = 120 */
Starting from 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] */
(If you want to know how to implement negative indexing in arrays, read this post please.)
let arrays: [[String]] = [["Hello","Hola","你好"], ["world","mundo","世界"]]
let helloWorld = arrays.compactMap { $0[0] }
print(helloWorld)
/* RESULT: ["Hello", "world"] */
One more example with key shortcut (Swift 5.6) and a subscript:
let dictionaries: [[_ : Any?]] = [[1: "x"], [2: nil], [3: true]]
let values = dictionaries.compactMap { $0[$0.startIndex].value }
print(values)
/* RESULT: ["x", true] */
Or look at the example of unordered set:
let collection: Set<String> = ["One", "", "Three"]
collection.map {
switch $0.isEmpty {
case true:
print("Empty")
case false:
print("Element \($0) isn't empty")
}
}
/* RESULT: "Element Three isn't empty" */
/* "Empty" */
/* "Element One isn't empty" */
let completionHandler: ((Bool) -> Void)? = {
if $0 {
print("It is true, sister...")
} else {
print("False")
}
}
completionHandler?(true)
/* RESULT: It is true, sister... */
Regular syntax, however, is as following:
let completionHandler: ((Bool) -> Void)? = { sayTheTruth in
if sayTheTruth {
print("It is true, sister...")
} else {
print("False")
}
}
completionHandler?(false)
/* RESULT: False */
let columns: [GridItem] = Array(repeating: .init(.fixed(70)), count: 5)
var body: some View {
ScrollView {
LazyVGrid(columns: columns) {
ForEach((1...10), id: \.self) {
Text("\($0)").frame(maxWidth: .infinity)
}
}
}
}
/* RESULT: 1 2 3 4 5 */
/* 6 7 8 9 10 */
Operator Method:
let records: [Int] = [110, 108, 107, 109, 108]
public func averageSpeed(records: [Int]) throws -> Int {
let average = records.reduce(0, +) / records.count
return average
}
try averageSpeed(records: records)
/* RESULT: 108 */
Shorthand Argument Names $0 and $1:
public func averageSpeed(records: [Int]) throws -> Int {
let average = records.reduce(0) { $0 + $1 } / records.count
return average
}
try averageSpeed(records: records)
/* RESULT: 108 */
.onChanged and .onEnded modifiers perform an @escaping closure when a SwiftUI gesture changed or ended.
@State private var rotate: Angle = .zero
var myGesture: some Gesture {
RotationGesture()
.onChanged { rotate = $0 }
.onEnded { angle in rotate = angle }
}
var body: some View {
Rectangle()
.rotationEffect(rotate)
.gesture(myGesture)
}
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
Kotlin's lambda expression has just one parameter with implicit name: it. In other words, if you have a function literal with exactly one parameter you don’t need to define that parameter explicitly, you can use it instead (like $0 in Swift).
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]
In Addition with @Bobby's Answer I would like to Add an Example
var add: (Int,Int,Int)->Int
add = {
//So here the $0 is first argument $1 is second argument $2 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