【发布时间】:2016-07-08 17:54:10
【问题描述】:
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)
谁能解释一下,$0 和 $1 在swift中是什么意思?
更多示例
array.forEach {
actions.append($0)
}
【问题讨论】:
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)
谁能解释一下,$0 和 $1 在swift中是什么意思?
更多示例
array.forEach {
actions.append($0)
}
【问题讨论】:
$0 是传入闭包的第一个参数。 $1 是第二个参数,等等。您显示的闭包是以下的简写:
let sortedNumbers = numbers.sort { (firstObject, secondObject) in
return firstObject > secondObject
}
【讨论】:
TL;DR
$0和$1是 Closure 的第一个和第二个速记参数(又名Shorthand Argument Names或SAN简称)。速记参数名称由 Swift 自动提供。第一个参数可以被$0引用,第二个参数可以被$1引用,第三个参数可以被$2引用,等等。
如您所知,Closure 是一个独立的功能块(没有名称的函数),可以在您的代码中传递和使用。闭包在其他编程语言中有不同的名称,含义也略有不同——在 Python 和 Kotlin 中是 Lambda,或 Block 在 C 和 Obj-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 uppercased = companies.map { (item) -> String in item.uppercased() }
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
map
let uppercased = companies.map { $0.uppercased() }
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
filter 中的 SANlet 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] */
可变参数函数是接受任意数量参数的函数。速记参数名称非常适合这种情况。
fileprivate func dessert(_ fruits: String...) -> Bool {
return fruits.contains { $0 == "Apple" }
}
let contains = dessert("Mango", "Durian", "apple")
print(contains)
/* RESULT: false */
$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、$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 dictionaries: [[Int8: Any?]] = [[1: "x"], [2: nil], [3: "z"]]
let values = dictionaries.compactMap { $0[$0.startIndex].value }
print(values)
/* RESULT: ["x", "z"] */
或者看看这个例子:
let sett: Set<String> = ["One", "", "Three"]
sett.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... */
但是,常规语法如下:
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 */
算子方法:
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 */
简写参数名称 $0 和 $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 */
另外,让我们看看 Kotlin 的 lambda 与 Swift 的闭包有何相似之处:
斯威夫特
let element: [String] = ["Argentum","Aurum","Platinum"]
let characterCount = element.map { $0.count }
print(characterCount)
/* RESULT: [8, 5, 8] */
科特林
通常 Kotlin 的 lambda 表达式只有一个隐含名称的参数: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]
【讨论】:
list(map(len, ....)) 就足够了。就个人而言,除非在关键性能部分,否则我会使用[len(v) for v in ...],因为它更简洁且更具可读性。
它表示发送到闭包中的简写参数,这个例子将其分解:
斯威夫特 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
【讨论】:
add = (+)
var add:((Int, Int) -> Int) = ... 明确指定案例 3 和 4 的类型。
引用排序的第一个和第二个参数。在这里,sort 比较 2 个元素并对它们进行排序。
您可以查找Swift official documentation 了解更多信息:
Swift 自动为内联提供速记参数名称 闭包,可用于引用闭包的值 名称为 $0、$1、$2 等的参数。
【讨论】:
除了@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
【讨论】:
它是简写的参数名称。
Swift 自动为内联闭包提供速记参数名称,可用于通过名称 $0、$1、$2 等来引用闭包参数的值。
如果您在闭包表达式中使用这些速记参数名称,您可以从其定义中省略闭包的参数列表,并且速记参数名称的数量和类型将从预期的函数类型中推断出来。 in 关键字也可以省略,因为闭包表达式完全由它的主体组成:
reversed = names.sort( { $0 > $1 } )
这里,$0 和 $1 指的是闭包的第一个和第二个字符串参数。
【讨论】: