Translations for Swift 4.1 (#777)
* Translations for Chapter 3 part 01 for Swift 4.0/4.1 * update chapter 3 part 02 for swift 4.1 * update chapter 3 part 03 for Swift 4.1 * update chapter 1 part 01 for Swift 4.1 * update chapter 1 part 02 for Swift 4.1 * update chapter 1 part 03 for Swift 4.1 * update chapter 2 part 01 for Swift 4.1 * update chapter 2 part 02 for Swift 4.1 * update chapter 2 part 3 for Swift 4.1 * update "summary" and corrected file names * update chapter 2 part 4 for Swift 4.1 * update chapter 2 part 5 for Swift 4.1 * update chapter 2 part 6 for Swift 4.1 * update chapter 2 parts 06-11 and other parts' errors * update chapter 2 parts 12-14 * update chapter 2 parts 14-19 * update all chapter 2 * update whole chapter 1 * update some parts of chapter 3
This commit is contained in:
@ -23,6 +23,9 @@
|
||||
> 4.0
|
||||
> 翻译:[muhlenXi](https://github.com/muhlenxi) 2017-09-21
|
||||
|
||||
> 4.1
|
||||
> 翻译+校对:[mylittleswift](https://github.com/mylittleswift)
|
||||
|
||||
本页包含内容:
|
||||
|
||||
- [存储属性的初始赋值](#setting_initial_values_for_stored_properties)
|
||||
@ -38,7 +41,7 @@
|
||||
|
||||
通过定义*构造器*来实现构造过程,就像用来创建特定类型新实例的特殊方法。与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。
|
||||
|
||||
类的实例也可以通过定义*析构器*在实例释放之前执行特定的清除工作。想了解更多关于析构器的内容,请参考[析构过程](./15_Deinitialization.html)。
|
||||
类的实例也可以通过定义*析构器*在实例释放之前执行特定的清除工作。想了解更多关于析构器的内容,请参考[析构过程](./15_Deinitialization.html)。
|
||||
|
||||
<a name="setting_initial_values_for_stored_properties"></a>
|
||||
## 存储属性的初始赋值
|
||||
@ -48,7 +51,8 @@
|
||||
你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下小节将详细介绍这两种方法。
|
||||
|
||||
> 注意
|
||||
当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者。
|
||||
>
|
||||
> 当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者。
|
||||
|
||||
<a name="initializers"></a>
|
||||
### 构造器
|
||||
@ -83,7 +87,8 @@ print("The default temperature is \(f.temperature)° Fahrenheit")
|
||||
如前所述,你可以在构造器中为存储型属性设置初始值。同样,你也可以在属性声明时为其设置默认值。
|
||||
|
||||
> 注意
|
||||
如果一个属性总是使用相同的初始值,那么为其设置一个默认值比每次都在构造器中赋值要好。两种方法的效果是一样的,只不过使用默认值让属性的初始化和声明结合得更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承等特性,后续章节将讲到。
|
||||
>
|
||||
> 如果一个属性总是使用相同的初始值,那么为其设置一个默认值比每次都在构造器中赋值要好。两种方法的效果是一样的,只不过使用默认值让属性的初始化和声明结合得更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承等特性,后续章节将讲到。
|
||||
|
||||
你可以使用更简单的方式在定义结构体 `Fahrenheit` 时为属性 `temperature` 设置默认值:
|
||||
|
||||
@ -101,7 +106,7 @@ struct Fahrenheit {
|
||||
<a name="initialization_parameters"></a>
|
||||
### 构造参数
|
||||
|
||||
自定义`构造过程`时,可以在定义中提供构造参数,指定参数值的类型和名字。构造参数的功能和语法跟函数和方法的参数相同。
|
||||
自定义构造过程时,可以在定义中提供*构造参数*,指定参数值的类型和名字。构造参数的功能和语法跟函数和方法的参数相同。
|
||||
|
||||
下面例子中定义了一个包含摄氏度温度的结构体 `Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)`和`init(fromKelvin:)`,二者分别通过接受不同温标下的温度值来创建新的实例:
|
||||
|
||||
@ -124,12 +129,12 @@ let freezingPointOfWater = Celsius(fromKelvin: 273.15)
|
||||
|
||||
第一个构造器拥有一个构造参数,其外部名字为`fromFahrenheit`,内部名字为`fahrenheit`;第二个构造器也拥有一个构造参数,其外部名字为`fromKelvin`,内部名字为`kelvin`。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性 `temperatureInCelsius` 中。
|
||||
|
||||
<a name="local_and_external_parameter_names"></a>
|
||||
### 参数的内部名称和外部名称
|
||||
<a name="parameter_names_and_argument_labels"></a>
|
||||
### 参数名和参数标签
|
||||
|
||||
跟函数和方法参数相同,构造参数也拥有一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参数名字。
|
||||
跟函数和方法参数相同,构造参数也拥有一个在构造器内部使用的参数名和一个在调用构造器时使用的参数标签。
|
||||
|
||||
然而,构造器并不像函数和方法那样在括号前有一个可辨别的名字。因此在调用构造器时,主要通过构造器中的参数名和类型来确定应该被调用的构造器。正因为参数如此重要,如果你在定义构造器时没有提供参数的外部名字,Swift 会为构造器的每个参数自动生成一个跟内部名字相同的外部名。
|
||||
然而,构造器并不像函数和方法那样在括号前有一个可辨别的名字。因此在调用构造器时,主要通过构造器中的参数名和类型来确定应该被调用的构造器。正因为参数如此重要,如果你在定义构造器时没有提供参数标签,Swift 会为构造器的*每个*参数自动生成一个参数标签。
|
||||
|
||||
以下例子中定义了一个结构体 `Color`,它包含了三个常量:`red`、`green` 和 `blue`。这些属性可以存储 `0.0` 到 `1.0` 之间的值,用来指示颜色中红、绿、蓝成分的含量。
|
||||
|
||||
@ -158,7 +163,7 @@ let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
|
||||
let halfGray = Color(white: 0.5)
|
||||
```
|
||||
|
||||
注意,如果不通过外部参数名字传值,你是没法调用这个构造器的。只要构造器定义了某个外部参数名,你就必须使用它,忽略它将导致编译错误:
|
||||
注意,如果不通过参数标签传值,你是没法调用这个构造器的。只要构造器定义了某个参数标签,你就必须使用它,忽略它将导致编译错误:
|
||||
|
||||
```swift
|
||||
let veryGreen = Color(0.0, 1.0, 0.0)
|
||||
@ -166,9 +171,9 @@ let veryGreen = Color(0.0, 1.0, 0.0)
|
||||
```
|
||||
|
||||
<a name="initializer_parameters_without_external_names"></a>
|
||||
### 不带外部名的构造器参数
|
||||
### 不带参数标签的构造器参数
|
||||
|
||||
如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线(`_`)来显式描述它的外部名,以此重写上面所说的默认行为。
|
||||
如果你不希望为构造器的某个参数提供参数标签,你可以使用下划线(`_`)来显式描述它的外部名,以此重写上面所说的默认行为。
|
||||
|
||||
下面是之前 `Celsius` 例子的扩展,跟之前相比添加了一个带有 `Double` 类型参数的构造器,其外部名用 `_` 代替:
|
||||
|
||||
@ -190,7 +195,7 @@ let bodyTemperature = Celsius(37.0)
|
||||
// bodyTemperature.temperatureInCelsius 为 37.0
|
||||
```
|
||||
|
||||
调用 `Celsius(37.0)` 意图明确,不需要外部参数名称。因此适合使用 `init(_ celsius: Double)` 这样的构造器,从而可以通过提供 `Double` 类型的参数值调用构造器,而不需要加上外部名。
|
||||
调用 `Celsius(37.0)` 意图明确,不需要参数标签。因此适合使用 `init(_ celsius: Double)` 这样的构造器,从而可以通过提供未命名的`Double`值调用构造器,而不需要加上参数标签。
|
||||
|
||||
<a name="optional_property_types"></a>
|
||||
### 可选属性类型
|
||||
@ -225,7 +230,8 @@ cheeseQuestion.response = "Yes, I do like cheese."
|
||||
你可以在构造过程中的任意时间点给常量属性指定一个值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
|
||||
|
||||
> 注意
|
||||
对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
|
||||
>
|
||||
> 对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
|
||||
|
||||
你可以修改上面的 `SurveyQuestion` 示例,用常量属性替代变量属性 `text`,表示问题内容 `text` 在`SurveyQuestion`的实例被创建之后不会再被修改。尽管 `text` 属性现在是常量,我们仍然可以在类的构造器中设置它的值:
|
||||
|
||||
@ -249,7 +255,7 @@ beetsQuestion.response = "I also like beets. (But not with cheese.)"
|
||||
<a name="default_initializers"></a>
|
||||
## 默认构造器
|
||||
|
||||
如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器(default initializers)。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例。
|
||||
如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个*默认构造器(default initializers)*。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例。
|
||||
|
||||
下面例子中创建了一个类 `ShoppingListItem`,它封装了购物清单中的某一物品的属性:名字(`name`)、数量(`quantity`)和购买状态 `purchase state`:
|
||||
|
||||
@ -267,7 +273,7 @@ var item = ShoppingListItem()
|
||||
<a name="memberwise_initializers_for_structure_types"></a>
|
||||
### 结构体的逐一成员构造器
|
||||
|
||||
除了上面提到的默认构造器,如果结构体没有提供自定义的构造器,它们将自动获得一个逐一成员构造器,即使结构体的存储型属性没有默认值。
|
||||
除了上面提到的默认构造器,如果结构体没有提供自定义的构造器,它们将自动获得一个*逐一成员构造器(memberwise initializer)*,即使结构体的存储型属性没有默认值。
|
||||
|
||||
逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。
|
||||
|
||||
@ -285,7 +291,7 @@ let twoByTwo = Size(width: 2.0, height: 2.0)
|
||||
<a name="initializer_delegation_for_value_types"></a>
|
||||
## 值类型的构造器代理
|
||||
|
||||
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能避免多个构造器间的代码重复。
|
||||
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为*构造器代理*,它能避免多个构造器间的代码重复。
|
||||
|
||||
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考[继承](./13_Inheritance.html)),这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节[类的继承和构造过程](#class_inheritance_and_initialization)中介绍。
|
||||
|
||||
@ -294,7 +300,8 @@ let twoByTwo = Size(width: 2.0, height: 2.0)
|
||||
请注意,如果你为某个值类型定义了一个自定义的构造器,你将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)。这种限制可以防止你为值类型增加了一个额外的且十分复杂的构造器之后,仍然有人错误的使用自动生成的构造器
|
||||
|
||||
> 注意
|
||||
假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(`extension`)中,而不是写在值类型的原始定义中。想查看更多内容,请查看[扩展](./21_Extensions.html)章节。
|
||||
>
|
||||
> 假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(`extension`)中,而不是写在值类型的原始定义中。想查看更多内容,请查看[扩展](./20_Extensions.html)章节。
|
||||
|
||||
下面例子将定义一个结构体 `Rect`,用来代表几何矩形。这个例子需要两个辅助的结构体 `Size` 和 `Point`,它们各自为其所有的属性提供了默认初始值 `0.0`。
|
||||
|
||||
@ -355,13 +362,14 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
|
||||
构造器 `init(center:size:)` 可以直接将 `origin` 和 `size` 的新值赋值到对应的属性中。然而,构造器 `init(center:size:)` 通过使用提供了相关功能的现有构造器将会更加便捷。
|
||||
|
||||
> 注意
|
||||
如果你想用另外一种不需要自己定义`init()`和`init(origin:size:)`的方式来实现这个例子,请参考[扩展](./21_Extensions.html)。
|
||||
>
|
||||
> 如果你想用另外一种不需要自己定义`init()`和`init(origin:size:)`的方式来实现这个例子,请参考[扩展](./21_Extensions.html)。
|
||||
|
||||
<a name="class_inheritance_and_initialization"></a>
|
||||
## 类的继承和构造过程
|
||||
|
||||
类里面的所有存储型属性——包括所有继承自父类的属性——都必须在构造过程中设置初始值。
|
||||
|
||||
类里面的所有存储型属性——包括所有继承自父类的属性——都*必须*在构造过程中设置初始值。
|
||||
[]()
|
||||
Swift 为类类型提供了两种构造器来确保实例中所有存储型属性都能获得初始值,它们分别是指定构造器和便利构造器。
|
||||
|
||||
<a name="designated_initializers_and_convenience_initializers"></a>
|
||||
@ -403,15 +411,15 @@ convenience init(parameters) {
|
||||
|
||||
##### 规则 1
|
||||
|
||||
指定构造器必须调用其直接父类的的指定构造器。
|
||||
指定构造器必须调用其直接父类的的指定构造器。
|
||||
|
||||
##### 规则 2
|
||||
|
||||
便利构造器必须调用*同*类中定义的其它构造器。
|
||||
便利构造器必须调用*同*类中定义的其它构造器。
|
||||
|
||||
##### 规则 3
|
||||
|
||||
便利构造器最后必须调用指定构造器。
|
||||
便利构造器最后必须调用指定构造器。
|
||||
|
||||
一个更方便记忆的方法是:
|
||||
|
||||
@ -427,7 +435,8 @@ convenience init(parameters) {
|
||||
子类中包含两个指定构造器和一个便利构造器。便利构造器必须调用两个指定构造器中的任意一个,因为它只能调用同一个类里的其他构造器。这满足了上面提到的规则 2 和 3。而两个指定构造器必须调用父类中唯一的指定构造器,这满足了规则 1。
|
||||
|
||||
> 注意
|
||||
这些规则不会影响类的实例如何创建。任何上图中展示的构造器都可以用来创建完全初始化的实例。这些规则只影响类的构造器如何实现。
|
||||
>
|
||||
> 这些规则不会影响类的实例如何创建。任何上图中展示的构造器都可以用来创建完全初始化的实例。这些规则只影响类的构造器如何实现。
|
||||
|
||||
下面图例中展示了一种涉及四个类的更复杂的类层级结构。它演示了指定构造器是如何在类层级中充当“管道”的作用,在类的构造器链上简化了类之间的相互关系。
|
||||
|
||||
@ -441,27 +450,28 @@ Swift 中类的构造过程包含两个阶段。第一个阶段,类中的每
|
||||
两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外地赋予不同的值。
|
||||
|
||||
> 注意
|
||||
Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1,Objective-C 给每一个属性赋值 `0` 或空值(比如说`0`或`nil`)。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以 `0` 或 `nil` 作为合法默认值的情况。
|
||||
>
|
||||
> Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1,Objective-C 给每一个属性赋值 `0` 或空值(比如说`0`或`nil`)。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以 `0` 或 `nil` 作为合法默认值的情况。
|
||||
|
||||
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程不出错地完成:
|
||||
|
||||
##### 安全检查 1
|
||||
|
||||
指定构造器必须保证它所在类的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器。
|
||||
指定构造器必须保证它所在类的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器。
|
||||
|
||||
如上所述,一个对象的内存只有在其所有存储型属性确定之后才能完全初始化。为了满足这一规则,指定构造器必须保证它所在类的属性在它往上代理之前先完成初始化。
|
||||
|
||||
##### 安全检查 2
|
||||
|
||||
指定构造器必须在为继承的属性设置新值之前向上代理调用父类构造器,如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖。
|
||||
指定构造器必须在为继承的属性设置新值之前向上代理调用父类构造器,如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖。
|
||||
|
||||
##### 安全检查 3
|
||||
|
||||
便利构造器必须为任意属性(包括同类中定义的)赋新值之前代理调用同一类中的其它构造器,如果没这么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖。
|
||||
便利构造器必须为任意属性(包括同类中定义的)赋新值之前代理调用同一类中的其它构造器,如果没这么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖。
|
||||
|
||||
##### 安全检查 4
|
||||
|
||||
构造器在第一阶段构造完成之前,不能调用任何实例方法,不能读取任何实例属性的值,不能引用`self`作为一个值。
|
||||
构造器在第一阶段构造完成之前,不能调用任何实例方法,不能读取任何实例属性的值,不能引用`self`作为一个值。
|
||||
|
||||
类实例在第一阶段结束以前并不是完全有效的。只有第一阶段完成后,该实例才会成为有效实例,才能访问属性和调用方法。
|
||||
|
||||
@ -509,7 +519,8 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
|
||||
跟 Objective-C 中的子类不同,Swift 中的子类默认情况下不会继承父类的构造器。Swift 的这种机制可以防止一个父类的简单构造器被一个更精细的子类继承,并被错误地用来创建子类的实例。
|
||||
|
||||
> 注意
|
||||
父类的构造器仅会在安全和适当的情况下被继承。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。
|
||||
>
|
||||
> 父类的构造器仅会在安全和适当的情况下被继承。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。
|
||||
|
||||
假如你希望自定义的子类中能提供一个或多个跟父类相同的构造器,你可以在子类中提供这些构造器的自定义实现。
|
||||
|
||||
@ -518,7 +529,8 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
|
||||
正如重写属性,方法或者是下标,`override` 修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否正确。
|
||||
|
||||
> 注意
|
||||
当你重写一个父类的指定构造器时,你总是需要写`override`修饰符,即使是为了实现子类的便利构造器。
|
||||
>
|
||||
> 当你重写一个父类的指定构造器时,你总是需要写`override`修饰符,即使是为了实现子类的便利构造器。
|
||||
|
||||
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文[类的构造器代理规则](#initializer_delegation_for_class_types)有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
|
||||
|
||||
@ -566,7 +578,8 @@ print("Bicycle: \(bicycle.description)")
|
||||
```
|
||||
|
||||
> 注意
|
||||
子类可以在初始化时修改继承来的变量属性,但是不能修改继承来的常量属性。
|
||||
>
|
||||
> 子类可以在初始化时修改继承来的变量属性,但是不能修改继承来的常量属性。
|
||||
|
||||
<a name="automatic_initializer_inheritance"></a>
|
||||
### 构造器的自动继承
|
||||
@ -577,16 +590,17 @@ print("Bicycle: \(bicycle.description)")
|
||||
|
||||
##### 规则 1
|
||||
|
||||
如果子类没有定义任何指定构造器,它将自动继承父类所有的指定构造器。
|
||||
如果子类没有定义任何指定构造器,它将自动继承父类所有的指定构造器。
|
||||
|
||||
##### 规则 2
|
||||
|
||||
如果子类提供了所有父类指定构造器的实现——无论是通过规则 1 继承过来的,还是提供了自定义实现——它将自动继承父类所有的便利构造器。
|
||||
如果子类提供了所有父类指定构造器的实现——无论是通过规则 1 继承过来的,还是提供了自定义实现——它将自动继承父类所有的便利构造器。
|
||||
|
||||
即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。
|
||||
|
||||
> 注意
|
||||
对于规则 2,子类可以将父类的指定构造器实现为便利构造器。
|
||||
>
|
||||
> 对于规则 2,子类可以将父类的指定构造器实现为便利构造器。
|
||||
|
||||
<a name="designated_and_convenience_initializers_in_action"></a>
|
||||
### 指定构造器和便利构造器实践
|
||||
@ -681,7 +695,8 @@ class ShoppingListItem: RecipeIngredient {
|
||||
```
|
||||
|
||||
> 注意
|
||||
`ShoppingListItem` 没有定义构造器来为 `purchased` 提供初始值,因为添加到购物单的物品的初始状态总是未购买。
|
||||
>
|
||||
> `ShoppingListItem` 没有定义构造器来为 `purchased` 提供初始值,因为添加到购物单的物品的初始状态总是未购买。
|
||||
|
||||
由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,`ShoppingListItem` 将自动继承所有父类中的指定构造器和便利构造器。
|
||||
|
||||
@ -717,12 +732,14 @@ for item in breakfastList {
|
||||
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在 `init` 关键字后面添加问号 (`init?`)。
|
||||
|
||||
> 注意
|
||||
可失败构造器的参数名和参数类型,不能与其它非可失败构造器的参数名,及其参数类型相同。
|
||||
>
|
||||
> 可失败构造器的参数名和参数类型,不能与其它非可失败构造器的参数名,及其参数类型相同。
|
||||
|
||||
可失败构造器会创建一个类型为自身类型的可选类型的对象。你通过 `return nil` 语句来表明可失败构造器在何种情况下应该 “失败”。
|
||||
|
||||
> 注意
|
||||
严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用`return nil`表明可失败构造器构造失败,而不要用关键字`return`来表明构造成功。
|
||||
>
|
||||
> 严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用`return nil`表明可失败构造器构造失败,而不要用关键字`return`来表明构造成功。
|
||||
|
||||
例如,实现针对数字类型转换的可失败构造器。确保数字类型之间的转换能保持精确的值,使用这个 `init(exactly:)` 构造器。如果类型转换不能保持值不变,则这个构造器构造失败。
|
||||
|
||||
@ -783,7 +800,8 @@ if anonymousCreature == nil {
|
||||
```
|
||||
|
||||
> 注意
|
||||
空字符串(如 `""`,而不是 `"Giraffe"` )和一个值为 `nil` 的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们之所以让 `Animal` 的可失败构造器构造失败,只是因为对于 `Animal` 这个类的 `species` 属性来说,它更适合有一个具体的值,而不是空字符串。
|
||||
>
|
||||
> 空字符串(如 `""`,而不是 `"Giraffe"` )和一个值为 `nil` 的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们之所以让 `Animal` 的可失败构造器构造失败,只是因为对于 `Animal` 这个类的 `species` 属性来说,它更适合有一个具体的值,而不是空字符串。
|
||||
|
||||
<a name="failable_nitializers_for_enumerations"></a>
|
||||
### 枚举类型的可失败构造器
|
||||
@ -859,7 +877,8 @@ if unknownUnit == nil {
|
||||
无论是向上代理还是横向代理,如果你代理到的其他可失败构造器触发构造失败,整个构造过程将立即终止,接下来的任何构造代码不会再被执行。
|
||||
|
||||
> 注意
|
||||
可失败构造器也可以代理到其它的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。
|
||||
>
|
||||
> 可失败构造器也可以代理到其它的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。
|
||||
|
||||
下面这个例子,定义了一个名为`CartItem`的`Product`类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为`quantity`的常量存储型属性,并确保该属性的值至少为`1`:
|
||||
|
||||
@ -923,7 +942,8 @@ if let oneUnnamed = CartItem(name: "", quantity: 1) {
|
||||
注意,当你用子类的非可失败构造器重写父类的可失败构造器时,向上代理到父类的可失败构造器的唯一方式是对父类的可失败构造器的返回值进行强制解包。
|
||||
|
||||
> 注意
|
||||
你可以用非可失败构造器重写可失败构造器,但反过来却不行。
|
||||
>
|
||||
> 你可以用非可失败构造器重写可失败构造器,但反过来却不行。
|
||||
|
||||
下例定义了一个名为 `Document` 的类,`name` 属性的值必须为一个非空字符串或 `nil`,但不能是一个空字符串:
|
||||
|
||||
@ -974,7 +994,7 @@ class UntitledDocument: Document {
|
||||
在这个例子中,如果在调用父类的可失败构造器 `init?(name:)` 时传入的是空字符串,那么强制解包操作会引发运行时错误。不过,因为这里是通过非空的字符串常量来调用它,所以并不会发生运行时错误。
|
||||
|
||||
<a name="the_init!_failable_initializer"></a>
|
||||
### 可失败构造器 init!
|
||||
### init!可失败构造器
|
||||
|
||||
通常来说我们通过在`init`关键字后添加问号的方式(`init?`)来定义一个可失败构造器,但你也可以通过在`init`后面添加惊叹号的方式来定义一个可失败构造器(`init!`),该可失败构造器将会构建一个对应类型的隐式解包可选类型的对象。
|
||||
|
||||
@ -1004,7 +1024,8 @@ class SomeSubclass: SomeClass {
|
||||
```
|
||||
|
||||
> 注意
|
||||
如果子类继承的构造器能满足必要构造器的要求,则无须在子类中显式提供必要构造器的实现。
|
||||
>
|
||||
> 如果子类继承的构造器能满足必要构造器的要求,则无须在子类中显式提供必要构造器的实现。
|
||||
|
||||
<a name="setting_a_default_property_value_with_a_closure_or_function"></a>
|
||||
## 通过闭包或函数设置属性的默认值
|
||||
@ -1028,7 +1049,8 @@ class SomeClass {
|
||||
注意闭包结尾的花括号后面接了一对空的小括号。这用来告诉 Swift 立即执行此闭包。如果你忽略了这对括号,相当于将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。
|
||||
|
||||
> 注意
|
||||
如果你使用闭包来初始化属性,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能在闭包里访问其它属性,即使这些属性有默认值。同样,你也不能使用隐式的 `self` 属性,或者调用任何实例方法。
|
||||
>
|
||||
> 如果你使用闭包来初始化属性,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能在闭包里访问其它属性,即使这些属性有默认值。同样,你也不能使用隐式的 `self` 属性,或者调用任何实例方法。
|
||||
|
||||
下面例子中定义了一个结构体 `Chessboard`,它构建了西洋跳棋游戏的棋盘,西洋跳棋游戏在一副黑白格交替的 8 x 8 的棋盘中进行的:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user