Swift 闭包中的 $0 和 $1 是啥意思?
Posted
技术标签:
【中文标题】Swift 闭包中的 $0 和 $1 是啥意思?【英文标题】:What does $0 and $1 mean in Swift Closures?Swift 闭包中的 $0 和 $1 是什么意思? 【发布时间】:2016-07-08 17:54:10 【问题描述】:let sortedNumbers = numbers.sort $0 > $1
print(sortedNumbers)
谁能解释一下,$0
和 $1
在swift中是什么意思?
更多示例
array.forEach
actions.append($0)
【问题讨论】:
【参考方案1】:$0
是传入闭包的第一个参数。 $1
是第二个参数,等等。您显示的闭包是以下的简写:
let sortedNumbers = numbers.sort (firstObject, secondObject) in
return firstObject > secondObject
【讨论】:
我可以在闭包中使用第一个参数和第二个参数编写我自己的逻辑吗? 是的,这就是关闭的全部目的。 谢谢老兄,你的回答帮助我理解了闭包更好的部分【参考方案2】:TL;DR
斯威夫特 5.5
$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"] */
HOF 中的简写参数名称 map
let uppercased = companies.map $0.uppercased()
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
带有余数运算符的 HOF filter
中的 SAN
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] */
可变参数函数中的 SAN
可变参数函数是接受任意数量参数的函数。速记参数名称非常适合这种情况。
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 */
五个 SAN——$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 */
SwiftUI 中 ForEach 结构中的 SAN
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 */
运算符方法与 SAN
算子方法:
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 */
Swift vs Kotlin vs Python
另外,让我们看看 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]
【讨论】:
您的 Python 示例不必要地使用了 lambda。list(map(len, ....))
就足够了。就个人而言,除非在关键性能部分,否则我会使用[len(v) for v in ...]
,因为它更简洁且更具可读性。
请添加快速文档链接
@AndyFedoroff 官方文档【参考方案3】:
它表示发送到闭包中的简写参数,这个例子将其分解:
斯威夫特 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 = (+)
在我的 swift 5 测试中,它应该使用var add:((Int, Int) -> Int) = ...
明确指定案例 3 和 4 的类型。【参考方案4】:
引用排序的第一个和第二个参数。在这里,sort
比较 2 个元素并对它们进行排序。
您可以查找Swift official documentation 了解更多信息:
Swift 自动为内联提供速记参数名称 闭包,可用于引用闭包的值 名称为 $0、$1、$2 等的参数。
【讨论】:
【参考方案5】:除了@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 的答案 哈哈 - 我实际上投了赞成票,但是,我在第一段之后停止阅读闭包定义。我同意,这不是一个答案,它是整个 Swift 文档关于闭包的转录。【参考方案6】:它是简写的参数名称。
Swift 自动为内联闭包提供速记参数名称,可用于通过名称 $0、$1、$2 等来引用闭包参数的值。
如果您在闭包表达式中使用这些速记参数名称,您可以从其定义中省略闭包的参数列表,并且速记参数名称的数量和类型将从预期的函数类型中推断出来。 in 关键字也可以省略,因为闭包表达式完全由它的主体组成:
reversed = names.sort( $0 > $1 )
这里,$0 和 $1 指的是闭包的第一个和第二个字符串参数。
【讨论】:
以上是关于Swift 闭包中的 $0 和 $1 是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章
在 IntelliJ IDEA 中调试 Java 期间生成的变量名称中的美元符号是啥意思?是闭包吗?
Swift:viewDidLayoutSubviews 是啥意思?