【问题标题】: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)
}

【问题讨论】:

    标签: arrays swift closures


    【解决方案1】:

    $0 是传入闭包的第一个参数。 $1 是第二个参数,等等。您显示的闭包是以下的简写:

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

    【讨论】:

    • 我可以在闭包中使用第一个参数和第二个参数编写我自己的逻辑吗?
    • 是的,这就是关闭的全部目的。
    • 谢谢老兄,你的回答帮助我理解了闭包更好的部分
    【解决方案2】:

    TL;DR

    斯威夫特 5.5

    $0$1 是 Closure 的第一个和第二个速记参数(又名 Shorthand Argument NamesSAN 简称)。速记参数名称由 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) -&gt; 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 指的是闭包的第一个和第二个字符串参数。

      【讨论】:

        猜你喜欢
        • 2017-05-31
        • 2018-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-27
        • 2023-02-02
        • 2022-01-23
        相关资源
        最近更新 更多