Swift闭包中的$ 0和$ 1是什么意思?


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

谁能解释什么$0$1手段迅速?

更多样品

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

Answers:


119

$0是传递给闭包的第一个参数。$1是第二个参数,以此类推。您显示的闭包是以下内容的简写:

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

我可以使用第一个参数和第二个参数在闭包中编写自己的逻辑吗?
aashish tamsya,2016年

4
是的,这就是关闭的全部目的。
AdamPro13 '16

2
谢谢队友,您的回答帮助我了解了封口的更多内容
aashish tamsya 16-3-22

43

TL; DR

迅捷5.3

$0$1是Closure的第一个和第二个速记参数(akaShorthand Argument NamesSAN简称)。速记参数名称由Swift自动提供。第一个参数可以由引用$0,第二个参数可以由引用$1,第三个参数可以由引用$2,依此类推。

如您所知,Closure是一个自包含的功能块(一个没有名称的函数),可以在代码中传递和使用。关闭有意味其他编程语言,以及细微的差别不同的名字-这是LAMBDA的Python科特林阻止ç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"] */

HOFmap中带点标记的SAN

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

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


HOF中的SANfilter与剩余运算符

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 */


五个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 completionHandler: (Bool) -> Void = {
    if $0 {
        print("It is true, sister...")
    }
}

但是,常规语法如下:

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


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

蟒蛇

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 ...]它,因为它更干净且更具可读性。
马丁·彼得斯

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 = (+)
Samah

var add:((Int, Int) -> Int) = ...在我的swift 5测试中,应该为情况3和4明确指定类型。
Itachi

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引用闭包的第一个和第二个String参数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.