Merge remote-tracking branch 'upstream/gh-pages' into gh-pages

# Conflicts:
#	README.md
#	source/chapter3/06_Declarations.md
This commit is contained in:
Nemocdz
2019-06-26 23:55:25 +08:00
6 changed files with 2227 additions and 2225 deletions

View File

@ -5,8 +5,6 @@
[英文原版在线版](https://docs.swift.org/swift-book/) [英文原版在线版](https://docs.swift.org/swift-book/)
[英文原版ePub版](https://docs.swift.org/swift-book/TheSwiftProgrammingLanguageSwift5.epub)
# 在线阅读 # 在线阅读
使用 GitBook 制作,可以直接 [在线阅读](https://swiftgg.gitbook.io/swift/)。 使用 GitBook 制作,可以直接 [在线阅读](https://swiftgg.gitbook.io/swift/)。

View File

@ -430,7 +430,6 @@ struct Point {
```swift ```swift
{ (parameters) -> return type in { (parameters) -> return type in
>
statements statements
} }
``` ```
@ -448,7 +447,6 @@ struct Point {
```swift ```swift
myFunction { myFunction {
(x: Int, y: Int) -> Int in (x: Int, y: Int) -> Int in
>
return x + y return x + y
} }
@ -729,7 +727,6 @@ let myGreeting = greetings[keyPath: \[String].[1]]
var index = 2 var index = 2
let path = \[String].[index] let path = \[String].[index]
let fn: ([String]) -> String = { strings in strings[index] } let fn: ([String]) -> String = { strings in strings[index] }
>
print(greetings[keyPath: path]) print(greetings[keyPath: path])
// 打印 "bonjour" // 打印 "bonjour"
@ -840,7 +837,6 @@ extension SomeClass {
func doSomething(_ x: String) { } func doSomething(_ x: String) { }
} }
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void) let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
>
``` ```
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。 由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
@ -1036,7 +1032,6 @@ class SomeSubClass: SomeSuperClass {
```swift ```swift
// 类型注解是必须的,因为 String 类型有多种构造器 // 类型注解是必须的,因为 String 类型有多种构造器
let initializer: Int -> String = String.init let initializer: Int -> String = String.init
>
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +) let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +)
print(oneTwoThree) print(oneTwoThree)
// 打印“123” // 打印“123”
@ -1106,7 +1101,6 @@ let b = instance.someMethod(_:y:) // 无歧义
let d = instance.overloadedMethod // 有歧义 let d = instance.overloadedMethod // 有歧义
let d = instance.overloadedMethod(_:y:) // 有歧义 let d = instance.overloadedMethod(_:y:) // 有歧义
let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义 let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
>
``` ```
如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用: 如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用:
@ -1115,7 +1109,6 @@ let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
let x = [10, 3, 20, 15, 4] let x = [10, 3, 20, 15, 4]
.sort() .sort()
.filter { $0 > 5 } .filter { $0 > 5 }
>
.map { $0 * 100 } .map { $0 * 100 }
``` ```
@ -1232,7 +1225,6 @@ if let unwrappedC = c {
```swift ```swift
func someFunctionWithSideEffects() -> Int { func someFunctionWithSideEffects() -> Int {
>
// 译者注:为了能看出此函数是否被执行,加上了一句打印 // 译者注:为了能看出此函数是否被执行,加上了一句打印
print("someFunctionWithSideEffects") print("someFunctionWithSideEffects")
return 42 return 42

View File

@ -137,7 +137,7 @@ print("The second number is \(secondNumber).")
当常量名称的类型(`:` 类型)可以被推断出时,类型注解在常量声明中是可选的,正如 [类型推断](./03_Types.md#type_inference) 中所描述的。 当常量名称的类型(`:` 类型)可以被推断出时,类型注解在常量声明中是可选的,正如 [类型推断](./03_Types.md#type_inference) 中所描述的。
声明一个常量类型属性要使用 `static` 声明修饰符。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties)中有介绍。 声明一个常量类型属性要使用 `static` 声明修饰符。类的常量类型属性总是隐式地被标记为 `final` ;你无法用 `class``final` 声明修饰符实现允许或禁止被子类重写的目的。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 中有介绍。
如果还想获得更多关于常量的信息或者想在使用中获得帮助,请参阅 [常量和变量](../chapter2/01_The_Basics.md#constants_and_variables) 和 [存储属性](../chapter2/10_Properties.md#stored_properties)。 如果还想获得更多关于常量的信息或者想在使用中获得帮助,请参阅 [常量和变量](../chapter2/01_The_Basics.md#constants_and_variables) 和 [存储属性](../chapter2/10_Properties.md#stored_properties)。
@ -251,11 +251,6 @@ var 变量名称: 类型 = 表达式 {
### 类型变量属性 {#type-variable-properties} ### 类型变量属性 {#type-variable-properties}
要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。 要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。
> 注意
>
> 在一个类声明中,使用关键字 `static` 与同时使用 `class` 和 `final` 去标记一个声明的效果相同。
>
#### grammer_of_a_variable_declaration {#grammer-of-a-variable-declaration} #### grammer_of_a_variable_declaration {#grammer-of-a-variable-declaration}
> 变量声明语法 > 变量声明语法
@ -356,20 +351,16 @@ typealias 类型别名 = 现存类型
```swift ```swift
typealias StringDictionary<Value> = Dictionary<String, Value> typealias StringDictionary<Value> = Dictionary<String, Value>
>
// 下列两个字典拥有同样的类型 // 下列两个字典拥有同样的类型
var dictionary1: StringDictionary<Int> = [:] var dictionary1: StringDictionary<Int> = [:]
>
var dictionary2: Dictionary<String, Int> = [:] var dictionary2: Dictionary<String, Int> = [:]
>
``` ```
当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如: 当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如:
```swift ```swift
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int> typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
>
``` ```
因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。 因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。
@ -389,7 +380,6 @@ protocol Sequence {
} }
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int { func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
>
// ... // ...
} }
``` ```
@ -424,7 +414,6 @@ func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
```swift ```swift
func 函数名称(参数列表) -> 返回类型 { func 函数名称(参数列表) -> 返回类型 {
>
语句 语句
} }
``` ```
@ -439,6 +428,8 @@ func 函数名称(参数列表) {
每个参数的类型都要标明,因为它们不能被推断出来。如果您在某个参数类型前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。 每个参数的类型都要标明,因为它们不能被推断出来。如果您在某个参数类型前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
函数声明中语句只包含一个表达式,可以理解为返回该表达式的值。
函数可以使用元组类型作为返回类型来返回多个值。 函数可以使用元组类型作为返回类型来返回多个值。
函数定义可以出现在另一个函数声明内。这种函数被称作*嵌套函数nested function*。 函数定义可以出现在另一个函数声明内。这种函数被称作*嵌套函数nested function*。
@ -456,7 +447,6 @@ func 函数名称(参数列表) {
```swift ```swift
func f(x: Int, y: Int) -> Int { return x + y } func f(x: Int, y: Int) -> Int { return x + y }
>
f(x: 1, y: 2) // 参数 x 和 y 都有标签 f(x: 1, y: 2) // 参数 x 和 y 都有标签
``` ```
@ -495,7 +485,6 @@ repeatGreeting("Hello, world!", count: 2) // count 有标签, greeting 没有
```swift ```swift
func someFunction(a: inout Int) -> () -> Int { func someFunction(a: inout Int) -> () -> Int {
>
return { [a] in return a + 1 } return { [a] in return a + 1 }
} }
``` ```
@ -535,7 +524,7 @@ _ : 参数类型
```swift ```swift
func f(x: Int = 42) -> Int { return x } func f(x: Int = 42) -> Int { return x }
>
f() // 有效,使用默认值 f() // 有效,使用默认值
f(7) // 有效,提供了值 f(7) // 有效,提供了值
f(x: 7) // 无效,该参数没有外部名称 f(x: 7) // 无效,该参数没有外部名称
@ -546,14 +535,13 @@ f(x: 7) // 无效,该参数没有外部名称
子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者被 `override` 修饰符修饰的方法并未对超类方法构成重写,都会导致编译错误。 子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者被 `override` 修饰符修饰的方法并未对超类方法构成重写,都会导致编译错误。
枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。类中使用 `class` 声明修饰的方法可以被子类实现重写;类中使用 `static` 声明修饰的方法不可被重写。 枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。类中使用 `class` 声明修饰的方法可以被子类实现重写;类中使用 `class final` `static` 声明修饰的方法不可被重写。
### 抛出错误的函数和方法 {#throwing-functions-and-methods} ### 抛出错误的函数和方法 {#throwing-functions-and-methods}
可以抛出错误的函数或方法必须使用 `throws` 关键字标记。这类函数和方法被称为抛出函数和抛出方法。它们有着下面的形式: 可以抛出错误的函数或方法必须使用 `throws` 关键字标记。这类函数和方法被称为抛出函数和抛出方法。它们有着下面的形式:
```swift ```swift
func 函数名称(参数列表) throws -> 返回类型 { func 函数名称(参数列表) throws -> 返回类型 {
>
语句 语句
} }
``` ```
@ -571,7 +559,6 @@ func 函数名称(参数列表) throws -> 返回类型 {
```swift ```swift
func someFunction(callback: () throws -> Void) rethrows { func someFunction(callback: () throws -> Void) rethrows {
>
try callback() try callback()
} }
``` ```
@ -583,7 +570,6 @@ func alwaysThrows() throws {
throw SomeError.error throw SomeError.error
} }
func someFunction(callback: () throws -> Void) rethrows { func someFunction(callback: () throws -> Void) rethrows {
>
do { do {
try callback() try callback()
try alwaysThrows() // 非法, alwaysThrows() 不是一个抛出函数类型的参数 try alwaysThrows() // 非法, alwaysThrows() 不是一个抛出函数类型的参数
@ -711,7 +697,6 @@ enum Number {
} }
// f 的类型为 (Int) -> Number // f 的类型为 (Int) -> Number
>
let f = Number.integer let f = Number.integer
// 利用 f 把一个整数数组转成 Number 数组 // 利用 f 把一个整数数组转成 Number 数组
@ -727,7 +712,6 @@ let evenInts: [Number] = [0, 2, 4, 6].map(f)
```swift ```swift
enum Tree<T> { enum Tree<T> {
>
case empty case empty
indirect case node(value: T, left: Tree, right:Tree) indirect case node(value: T, left: Tree, right:Tree)
} }
@ -1092,7 +1076,9 @@ var 属性名: 类型 { get set }
同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了 getter 和 setter 要求,你不能在协议中直接实现 getter 和 setter。 同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了 getter 和 setter 要求,你不能在协议中直接实现 getter 和 setter。
符合类型可以通过多种方式满足 getter 和 setter 要求。如果属性声明包含 `get``set` 关键字,符合类型就可以用存储型变量属性或可读可写的计算型属性来满足此要求,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含 `get` 关键字的话,它可以作为任意类型的属性被实现。关于如何实现协议中的属性要求的例子,请参阅 [属性要求](../chapter2/21_Protocols.md#property_requirements) 符合类型可以通过多种方式满足 getter 和 setter 要求。如果属性声明包含 `get``set` 关键字,符合类型就可以用存储型变量属性或可读可写的计算型属性来满足此要求,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含 `get` 关键字的话,它可以作为任意类型的属性被实现。关于如何实现协议中的属性要求的例子,请参阅 [属性要求](../chapter2/21_Protocols.md#property_requirements)
协议声明中声明一个类型属性,属性声明语句必须用 `static` 声明修饰符。当结构体和枚举遵循该协议时,使用 `static` 关键字修饰,而类遵循该协议时,使用 `static``class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为类属性提供默认实现时,必须使用 `static` 关键字修饰。
另请参阅 [变量声明](#variable_declaration)。 另请参阅 [变量声明](#variable_declaration)。
@ -1109,7 +1095,7 @@ var 属性名: 类型 { get set }
### 协议方法声明 {#protocol-method-declaration} ### 协议方法声明 {#protocol-method-declaration}
协议可以通过在协议声明主体中引入一个协议方法声明,来声明符合的类型必须实现的方法。协议方法声明和函数方法声明有着相同的形式,但有两项例外:它们不包括函数体,也不能包含默认参数。关于如何实现协议中的方法要求的例子,请参阅 [方法要求](../chapter2/21_Protocols.md#method_requirements)。 协议可以通过在协议声明主体中引入一个协议方法声明,来声明符合的类型必须实现的方法。协议方法声明和函数方法声明有着相同的形式,但有两项例外:它们不包括函数体,也不能包含默认参数。关于如何实现协议中的方法要求的例子,请参阅 [方法要求](../chapter2/21_Protocols.md#method_requirements)。
使用 `static` 声明修饰符可以在协议声明中声明一个类型方法。类在实现这些方法时使用 `class` 声明修饰符。结构体实现这些方法时必须使用 `static` 声明修饰符。通过扩展实现时亦是如此(类的扩展中使用 `class` 声明修饰符,结构体的扩展中使用 `static` 声明修饰符) 协议声明中声明一个类型方法,方法声明语句必须用 `static` 声明修饰符。结构体和枚举遵循协议时,必须使用 `static` 关键字修饰,而类遵循协议时,使用 `static``class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为类方法提供默认实现时,必须使用 `static` 关键字修饰
另请参阅 [函数声明](#function_declaration)。 另请参阅 [函数声明](#function_declaration)。
@ -1150,11 +1136,12 @@ var 属性名: 类型 { get set }
```swift ```swift
subscript (参数列表) -> 返回类型 { get set } subscript (参数列表) -> 返回类型 { get set }
>
``` ```
下标声明只为符合类型声明了 getter 和 setter 要求。如果下标声明包含 `get``set` 关键字,符合类型也必须实现 getter 和 setter 子句。如果下标声明只包含 `get` 关键字,符合类型必须实现 getter 子句,可以选择是否实现 setter 子句。 下标声明只为符合类型声明了 getter 和 setter 要求。如果下标声明包含 `get``set` 关键字,符合类型也必须实现 getter 和 setter 子句。如果下标声明只包含 `get` 关键字,符合类型必须实现 getter 子句,可以选择是否实现 setter 子句。
协议声明中声明一个静态下标,下标声明语句必须用 `static` 声明修饰符。当结构体和枚举遵循该协议时,下标声明使用 `static` 关键字修饰,而类遵循该协议时,使用 `static``class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为下标声明提供默认实现时,必须使用 `static` 关键字修饰。
另请参阅 [下标声明](#subscript_declaration)。 另请参阅 [下标声明](#subscript_declaration)。
@ -1441,18 +1428,15 @@ doSomething(with: oneAndTwo)
```swift ```swift
protocol Serializable { protocol Serializable {
func serialize() -> Any func serialize() -> Any
>
} }
extension Array: Serializable where Element == Int { extension Array: Serializable where Element == Int {
func serialize() -> Any { func serialize() -> Any {
>
// implementation // implementation
} }
} }
extension Array: Serializable where Element == String { extension Array: Serializable where Element == String {
func serialize() -> Any { func serialize() -> Any {
>
// implementation // implementation
} }
} }
@ -1468,7 +1452,6 @@ extension String: SerializableInArray { }
extension Array: Serializable where Element: SerializableInArray { extension Array: Serializable where Element: SerializableInArray {
func serialize() -> Any { func serialize() -> Any {
>
// 具体实现 // 具体实现
} }
} }
@ -1536,7 +1519,6 @@ extension Array: Loggable where Element: MarkedLoggable { }
```swift ```swift
subscript (参数列表) -> 返回类型 { subscript (参数列表) -> 返回类型 {
>
get { get {
语句 语句
} }
@ -1552,16 +1534,21 @@ subscript (参数列表) -> 返回类型 {
和计算型属性一样下标声明支持对元素的读写操作。getter 用于读取值setter 用于写入值。setter 子句是可选的,当仅需要一个 getter 子句时,可以将二者都忽略,直接返回请求的值即可。但是,如果提供了 setter 子句,就必须提供 getter 子句。 和计算型属性一样下标声明支持对元素的读写操作。getter 用于读取值setter 用于写入值。setter 子句是可选的,当仅需要一个 getter 子句时,可以将二者都忽略,直接返回请求的值即可。但是,如果提供了 setter 子句,就必须提供 getter 子句。
圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 名称的类型必须与返回类型相同。 圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 的参数类型必须与返回类型相同。
可以重写下标,只要参数列表或返回类型不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。 可以重写下标,只要参数列表或返回类型不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。
默认情况下,下标中的参数不会含有 下标参数遵循与函数参数相同的规则,但有两个例外。默认情况下,下标中使用的参数不需要指定标签,这与函数,方法和构造器不同。但是你也可以同它们一样,显式地提供参数标签。此外,下标不能有 `In-out` 参数。
同样可以在协议声明中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。 同样可以在协议声明中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。
更多关于下标的信息和例子,请参阅 [下标](../chapter2/12_Subscripts.md)。 更多关于下标的信息和例子,请参阅 [下标](../chapter2/12_Subscripts.md)。
### 类型下标声明
声明一个由类型而不是类型实例公开的下标,请使用 `static` 声明修饰符标记下标声明。类可以使用 `class` 声明修饰符标记类型计算属性,以允许子类重写父类的实现。在类声明中,`static` 关键字具有与用 `class``final` 声明修饰符标记声明相同的效果。
#### grammer_of_a_subscript_declaration {#grammer-of-a-subscript-declaration} #### grammer_of_a_subscript_declaration {#grammer-of-a-subscript-declaration}
> 下标声明语法 > 下标声明语法
@ -1731,6 +1718,10 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
## 声明修饰符 {#Declaration-Modifiers} ## 声明修饰符 {#Declaration-Modifiers}
声明修饰符都是关键字或上下文相关的关键字,可以修改一个声明的行为或者含义。可以在声明的特性(如果存在)和引入该声明的关键字之间,利用声明修饰符的关键字或上下文相关的关键字指定一个声明修饰符。 声明修饰符都是关键字或上下文相关的关键字,可以修改一个声明的行为或者含义。可以在声明的特性(如果存在)和引入该声明的关键字之间,利用声明修饰符的关键字或上下文相关的关键字指定一个声明修饰符。
`class`
该修饰符用于修饰任何类成员,表明是类自身的成员,而不是类实例的成员。父类中使用该修饰符标记或者未被 `final` 修饰符标记的成员,都允许被子类重写。
`dynamic` `dynamic`
该修饰符用于修饰任何兼容 Objective-C 的类的成员。访问被 `dynamic` 修饰符标记的类成员将总是由 Objective-C 运行时系统进行动态派发,而不会由编译器进行内联或消虚拟化。 该修饰符用于修饰任何兼容 Objective-C 的类的成员。访问被 `dynamic` 修饰符标记的类成员将总是由 Objective-C 运行时系统进行动态派发,而不会由编译器进行内联或消虚拟化。
@ -1755,6 +1746,10 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
该修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 `required` 修饰符修饰该构造器。 该修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 `required` 修饰符修饰该构造器。
`static`
该修饰符用于修饰结构体、类、枚举或协议的成员,表明是类型成员,而不是类型实例的成员。在类声明的作用范围内,使用 `static` 修饰符标记成员声明语句,同 `class``final` 修饰符具有相同的效果。但是类的常量类型属性是一个例外: `static` 没有问题,但是你无法为常量声明使用 `class``final` 修饰符。
`unowned` `unowned`
该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会引发运行时错误。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#unowned_references) 该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会引发运行时错误。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#unowned_references)

View File

@ -151,7 +151,6 @@ dial.dynamicallyCall(withArguments: [4, 1, 1])
@dynamicCallable @dynamicCallable
struct Repeater { struct Repeater {
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String { func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
>
return pairs return pairs
.map { label, count in .map { label, count in
repeatElement(label, count: count).joined(separator: " ") repeatElement(label, count: count).joined(separator: " ")
@ -183,7 +182,11 @@ repeatLabels(a: "four") // Error
该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。 该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。
在显式成员表达式中,如果没有成名指定成员,则该表达式被理解为对该类型的 `subscript(dynamicMemberLookup:)` 下标的调用,传递包含成员名称字符串的参数。下标的参数只需遵循 `ExpressibleByStringLiteral` 协议,返回值类型可以为任意类型。在大多数情况下,下标的参数是一个 `String` 值。例如: 在显式成员表达式中,如果没有成名指定成员,则该表达式被理解为对该类型的 `subscript(dynamicMemberLookup:)` 下标的调用,传递包含成员名称字符串的参数。下标接收参数既可以是键路径,也可以是成员名称字符串;如果你同时实现这两种方式的下标调用,那么以键路径参数方式为准。
`subscript(dynamicMemberLookup:)` 实现允许接收 [`KeyPath`](https://developer.apple.com/documentation/swift/keypath)[`WritableKeyPath`](https://developer.apple.com/documentation/swift/writablekeypath) 或 [`ReferenceWritableKeyPath`](https://developer.apple.com/documentation/swift/referencewritablekeypath) 类型的键路径参数。而遵循 [`ExpressibleByStringLiteral`](https://developer.apple.com/documentation/swift/expressiblebystringliteral) 协议,下标调用接收参数为成员名称字符串 —— 在大多数情况下,下标的参数是一个 `String` 值。下标返回值类型可以为任意类型。
根据成员名称来动态地查找成员,可以帮助我们创建一个包裹数据的包装类型,但该类型无法在编译时进行类型检查,例如其他语言的数据桥接到 Swift 语言时。例如:
```swift ```swift
@dynamicMemberLookup @dynamicMemberLookup
@ -191,7 +194,6 @@ struct DynamicStruct {
let dictionary = ["someDynamicMember": 325, let dictionary = ["someDynamicMember": 325,
"someOtherMember": 787] "someOtherMember": 787]
subscript(dynamicMember member: String) -> Int { subscript(dynamicMember member: String) -> Int {
>
return dictionary[member] ?? 1054 return dictionary[member] ?? 1054
} }
} }
@ -208,6 +210,24 @@ print(dynamic == equivalent)
// 打印“true” // 打印“true”
``` ```
根据键路径来动态地查找成员,可用于创建一个包裹数据的包装类型,该类型在编译时期进行类型检查。例如:
```swift
struct Point { var x, y: Int }
@dynamicMemberLookup
struct PassthroughWrapper<Value> {
var value: Value
subscript<T>(dynamicMember member: KeyPath<Value, T>) -> T {
get { return value[keyPath: member] }
}
}
let point = Point(x: 381, y: 431)
let wrapper = PassthroughWrapper(value: point)
print(wrapper.x)
```
### `GKInspectable` {#gkinspectable} ### `GKInspectable` {#gkinspectable}
应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。 应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。
@ -263,7 +283,7 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
- 父类有 `objc` 特性,且重写为子类的声明。 - 父类有 `objc` 特性,且重写为子类的声明。
- 遵循带有 `objc` 特性协议的声明。 - 遵循带有 `objc` 特性协议的声明。
- 带有 `IBAction``IBOutlet``IBDesignable``IBInspectable``NSManaged``GKInspectable` 特性的声明。 - 带有 `IBAction` `IBSegueAction``IBOutlet``IBDesignable``IBInspectable``NSManaged``GKInspectable` 特性的声明。
如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus` 如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus`
@ -315,11 +335,11 @@ class ExampleClass: NSObject {
### Interface Builder 使用的声明特性 {#declaration-attributes-used-by-interface-builder} ### Interface Builder 使用的声明特性 {#declaration-attributes-used-by-interface-builder}
`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction``IBOutlet``IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。 `Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction``IBSegueAction``IBOutlet``IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
`IBOutlet``IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。 `IBOutlet``IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
应用 `IBAction``IBOutlet``IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。 应用 `IBAction``IBSegueAction``IBOutlet``IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
## 类型特性 {#type-attributes} ## 类型特性 {#type-attributes}

View File

@ -228,7 +228,6 @@ default:
```swift ```swift
// 重载 ~= 运算符对字符串和整数进行比较 // 重载 ~= 运算符对字符串和整数进行比较
func ~=(pattern: String, value: Int) -> Bool { func ~=(pattern: String, value: Int) -> Bool {
>
return pattern == "\(value)" return pattern == "\(value)"
} }

View File

@ -21,7 +21,6 @@
```swift ```swift
func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T { func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T {
>
if x < y { if x < y {
return y return y
} }
@ -117,7 +116,6 @@ struct Dictionary<Key: Hashable, Value>: CollectionType, DictionaryLiteralConver
```swift ```swift
let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>
``` ```
如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。 如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。