> For the complete documentation index, see [llms.txt](https://gitbook.existorlive.cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gitbook.existorlive.cn/kai-fa-yu-yan-xue-xi/swift/7.-bi-bao/2.-bi-bao-biao-da-shi.md).

# 闭包表达式

**闭包表达式** 是一种构建**内联闭包**的方式，是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包。

```swift
{[capture list](paramList) -> returnType in 
    // closure code
}
```

闭包表达式由**捕获列表**，**参数列表**，**返回值**，以及**闭包函数体**组成。

通常**捕获列表**可以参略，会根据函数体中使用变量或常量自动捕获；

**Example**

```swift

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

// sorted需要的闭包类型 (String,String) -> Bool
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

```

## 1. 闭包中的类型推断

根据闭包需要的类型，可以在闭包定义时省略参数类型和返回类型的定义，根据闭包参数的类型来推断

```swift
// 省略参数类型和返回类型，根据(String,String) -> Bool来推断
reversedNames = names.sorted(by: { s1, s2 in
    return s1 > s2
})
```

## 2. 单表达式闭包的隐式返回

单行表达式闭包可以通过省略 `return` 关键字来隐式返回单行表达式的结果

```swift
// 省略return，隐式返回
reversedNames = names.sorted(by: { s1, s2 in
    s1 > s2
})
```

## 3. 参数名称缩写

Swift 自动为内联闭包提供了参数名称缩写功能，你可以直接通过 `$0`，`$1`，`$2` 来顺序调用闭包的参数.

如果你在闭包表达式中使用参数名称缩写，你可以在闭包定义中省略参数列表，并且对应参数名称缩写的类型会通过函数类型进行推断。in 关键字也同样可以被省略

```swift
reversedNames = names.sorted(by: { $0 > $1 } )
```

## 4. 运算符方法

实际上还有一种更简短的方式来编写上面例子中的闭包表达式

```swift
reversedNames = names.sorted(by: >)
```

## 5. 总结

> 虽然在定义闭包表达式时，有许多简易写法，但是为了保证代码可读性，尽量还是要保证必要的代码存在。

## 不同语言中闭包实现的对比

**闭包** 是能够捕获定义上下文中的变量或常量引用的可调用对象。可以在代码中传递和调用。

不同语言中也有相似的实现：

* C++中lambda表达式
  * lambda表达式支持值捕获和引用捕获
  * 值捕获默认不可以修改，但是将`lambda`声明为`mutable`支持修改；引用捕获能够修改取决于是否为常量
  * C++中lambda表达式是值类型
  * 底层实现是重载调用运算符的匿名类的匿名对象；捕获的变量是匿名类的数据成员；函数实现就是重载调用运算符函数
* OC中的Block
  * Block表达式支持值捕获，和`__block`捕获
  * 值捕获的值不可以修改；`__block`捕获可以修改
  * Block是引用类型
  * 底层实现是匿名OC类的匿名对象，函数实现保存在匿名类中的成员函数指针中；捕获的变量是匿名类的属性
* Swift中的闭包
  * 闭包中都是引用捕获
  * 捕获的值能够修改取决于是否为常量
  * 闭包是引用类型
