From f5c85a2eedecaa30f586d81cfcc9d4ae05208cf5 Mon Sep 17 00:00:00 2001 From: Nemocdz Date: Wed, 1 Jul 2020 21:46:15 +0800 Subject: [PATCH] expressions Swift 5.3 beta --- .../03_language_reference/04_Expressions.md | 74 +++++++++++++++---- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/source/03_language_reference/04_Expressions.md b/source/03_language_reference/04_Expressions.md index 43a980d5..9fcc9fee 100644 --- a/source/03_language_reference/04_Expressions.md +++ b/source/03_language_reference/04_Expressions.md @@ -9,7 +9,6 @@ Swift 中存在四种表达式:前缀表达式,二元表达式,基本表 #### expression {#expression} > *表达式* → [try 运算符](#try-operator)可选 [前缀表达式](#prefix-expression) [二元表达式列表](#binary-expressions)可选 -> #### expression-list {#expression-list} @@ -232,11 +231,18 @@ f(x as Any) 字面量 | 类型 | 值 :------------- | :---------- | :---------- -`#file` | `String` | 所在的文件名 +`#file` | `String` | 所在的文件名及模块 +`#filePath` | `String` | 所在的文件路径 `#line` | `Int` | 所在的行数 `#column` | `Int` | 所在的列数 `#function` | `String` | 所在的声明的名字 +`#dsohandle` | `UnsafeRawPointer` | 所使用的 DSO(动态共享对象)句柄 +`#file` 表达式的值的格式是 *module*/*file*,*file* 是表达式所在的文件名,*module* 是文件所所在的模块名。`#filePath` 表达式的字符串值是表达式所在的文件在整个文件系统里的路径。所有这些值可以被 `#sourceLocation` 改变,详见 [行控制语句](./05_Statements.md#line-control-statements)。 + +> 注意 +> +> 要解析 `#file` 表达式,第一个斜杠(/)之前的文本作为模块名,最后一个斜杠之后的文本作为文件名。将来,该字符串可能包含多个斜杠,例如 `MyModule/some/disambiguation/MyFile.swift`。 对于 `#function`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init` 或 `subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字。 @@ -288,7 +294,7 @@ Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者 > > *字面量表达式* → [数组字面量](#array-literal) | [字典字面量](#dictionary-literal) | [练习场字面量](#playground-literal) > -> *字面量表达式* → **#file** | **#line** | **#column** | **#function** +> *字面量表达式* → **#file** | **#filePath** | **#line** | **#column** | **#function** > @@ -757,7 +763,7 @@ print(count as Any) // 打印 "Optional(5)" ``` -可以混合使用各种 key-path 组件来访问一些深度嵌套类型的值。下面的代码通过组合不同的组件,使用 key-path 表达式访问了一个字典数组中不同的值和属性。 +可以混合使用各种 key path 组件来访问一些深度嵌套类型的值。下面的代码通过组合不同的组件,使用 key-path 表达式访问了一个字典数组中不同的值和属性。 ```swift let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17], @@ -773,6 +779,39 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth // 打印 "64" ``` +你可以在平时提供函数或者闭包的上下文里使用 key path 表达式。特别地,你可以用根类型是 `SomeType` 和路径产生 `Value` 类型值的 key path 表达式来替换类型是 `(SomeType) -> Value` 的函数或者闭包。 + +```swift +truct Task { + var description: String + var completed: Bool +} +var toDoList = [ + Task(description: "Practice ping-pong.", completed: false), + Task(description: "Buy a pirate costume.", completed: true), + Task(description: "Visit Boston in the Fall.", completed: false), +] + +// 下面两种写法是等价的。 +let descriptions = toDoList.filter(\.completed).map(\.description) +let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } +``` + +任何 key path 表达式的副作用发生的关键在于表达式在哪里被执行。例如,如果你在 key path 表达式中的一个下标里使用函数调用,该函数只会在表达式计算的时候调用一次,而不是每次这个 key path 被使用的时候。 + +```swift +func makeIndex() -> Int { + print("Made an index") + return 0 +} +// 下面这行调用 makeIndex()。 +let taskKeyPath = \[Task][makeIndex()] +// 打印 "Made an index" + +// 使用 taskKeyPath 不会再次调用 makeIndex()。 +let someTask = toDoList[keyPath: taskKeyPath] +``` + 关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple-ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple-ref/doc/uid/10000177i)。 > key-path 表达式语法 @@ -959,14 +998,17 @@ print(keyPath == c.getSomeKeyPath()) 如果函数声明中指定了参数的名字,那么在调用的时候也必须得写出来。这种函数调用表达式具有以下形式: > `函数名`(`参数名 1`: `参数 1`, `参数名 2`: `参数 2`) -> 如果函数的最后一个参数是函数类型,可以在函数调用表达式的尾部(右圆括号之后)加上一个闭包,该闭包会作为函数的最后一个参数。如下两种写法是等价的: ```swift -// someFunction 接受整数和闭包参数 +// someFunction 接受整型和闭包的实参 someFunction(x, f: {$0 == 13}) someFunction(x) {$0 == 13} + +// anotherFunction 接受一个整型和两个闭包的实参 +anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) }) +anotherFunction(x: x) { $0 == 13 } g: { print(99) } ``` 如果闭包是该函数的唯一参数,那么圆括号可以省略。 @@ -988,30 +1030,32 @@ myData.someMethod {$0 == 13} > > *函数调用表达式* → [后缀表达式](#postfix-expression) [函数调用参数子句](#function-call-argument-clause)可选 [尾随闭包](#trailing-closure) > +>#### function-call-argument-clause {#function-call-argument-clause} > -> -#### function-call-argument-clause {#function-call-argument-clause} -> > *函数调用参数子句* → **(** **)** | **(** [函数调用参数表](#function-call-argument-list) **)** > -> -#### function-call-argument-list {#function-call-argument-list} +> #### function-call-argument-list {#function-call-argument-list} > > *函数调用参数表* → [函数调用参数](#function-call-argument) | [函数调用参数](#function-call-argument) **,** [*函数调用参数表*](#function-call-argument-list) > > -#### function-call-argument {#function-call-argument} +> #### function-call-argument {#function-call-argument} > > *函数调用参数* → [表达式](#expression) | [标识符](02-Lexical-Structure.md#identifier) **:** [表达式](#expression) > > *函数调用参数* → [运算符](./02_Lexical_Structure.md#operator) | [标识符](./02-Lexical-Structure.md#identifier) **:** [运算符](./02-Lexical-Structure.md#operator) > -> -> -#### trailing-closure {#trailing-closure} +> #### trailing-closure {#trailing-closure} > > *尾随闭包* → [闭包表达式](#closure-expression) +> +> #### labeled-trailing-closures {#labeled-trailing-closures} > +> *标签尾随闭包集* → [标签尾随闭包](#labeled-trailing-closure) [标签尾随闭包集](#labeled-trailing-closures)可选 +> +> #### labeled-trailing-closure {#labeled-trailing-closure} +> *标签尾随闭包* → [标识符](./02-Lexical-Structure.md#identifier) **:** [闭包表达式](#closure-expression) + ### 构造器表达式 {#initializer-expression} *构造器表达式*用于访问某个类型的构造器,形式如下: