swift系列(二):闭包

1. 概述和背景

闭包 是可以在你的代码中传递和使用的独立功能块。Swift 中的闭包类似于其他编程语言中的匿名函数、lambda 表达式和代码块。

闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这个过程可以看作是将这些常量和变量 包含 在闭包的作用域内。 Swift 会为你管理在捕获过程中涉及到的所有内存操作。

全局函数和嵌套函数实际上也是特殊的闭包,闭包采用如下三种形式之一:

  • 全局函数是一个有名字但不会捕获任何值的闭包
  • 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
  • 闭包表达式是使用轻量级语法编写的匿名闭包,它们能够捕获其上下文中的值。

2. 闭包表达式的使用

本章将会基于sorted(by:)方法介绍闭包表达式的使用

2.1 一般形式语法

对于sorted(by:)方法的by参数,最直接的方法是使用函数作为闭包参数:

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// 1. 使用函数作为闭包传递给sorted方法
let sortedNames1 = names.sorted(by: backward)

除此之外,你可以使用内联闭包表达式作为sorted的闭包参数,闭包表达式的一般语法形式如下:

{ (<#parameters#>) -> <#return type#> in
   <#statements#>
}

与函数定义类似:

  • 有参数列表、返回类型和函数体

但是与函数定义不同的是:

  • 参数列表写在花括号{}里面
  • 用关键字in将参数列表和返回类型与函数体隔开

即上述sorted方法的调用可以写成一下形式:

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// 2. 使用完整的闭包表达式语法传递闭包给sorted函数
let sortedNames2 = names.sorted(by: {(str1: String, str2: String) -> Bool in
return str1 > str2})

2.2 类型推断

当闭包是作为参数传递给方法的, Swift 可以根据调用上下文推断其参数的类型和返回的值的类型:

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// 3. 由于排序闭包是作为参数传递给sorted的,所以它能够根据上下文推断参数类型和返回类型
let sortedNames3 = names.sorted(by: {str1, str2 in return str1 < str2})

2.3 隐式返回

当闭包仅包含一条返回语句时,可以省略return关键字:

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// 4. 单表达式闭包可以通过从其声明中省略 return 关键字来隐式返回其单表达式的结果
let sortedNames4 = names.sorted(by: {str1, str2 in str1 > str2})

2.4 简写参数名称

Swift自动为内联闭包提供了简写参数名称功能,你可以直接通过 $0、$1、$2 等来引用闭包参数的值,以此类推:

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// 5. Swift 自动为内联闭包提供了简写参数名称功能,你可以直接通过 $0、$1、$2 等来引用闭包参数的值,以此类推
let sortedNames5 = names.sorted(by: {$0 < $1})

2.5 尾随闭包

如果你需要将闭包表达式作为函数的最后一个参数传递给函数,并且闭包表达式很长,则可以将其编写为 尾随闭包:在函数调用的括号后编写一个尾随闭包,该尾随闭包仍然会作为该函数的一个参数

当一个闭包表达式是函数或方法的唯一参数,并且把该表达式写作尾随闭包,则在调用函数或方法时,无需在函数名或方法名后编写一对括号 ()

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// 6. 如果你需要将闭包表达式作为函数的最后一个参数传递给函数,并且闭包表达式很长,则可以将其编写为 尾随闭包:在函数调用的括号后编写一个尾随闭包,该尾随闭包仍然会作为该函数的一个参数
// 当一个闭包表达式是函数或方法的唯一参数,并且把该表达式写作尾随闭包,则在调用函数或方法时,无需在函数名或方法名后编写一对括号 ()
let sortedNames6 = names.sorted {$0 > $1}

发表回复