@ -11,7 +11,7 @@
|
||||
- [类和结构体的选择](#choosing_between_classes_and_structures)
|
||||
- [集合(collection)类型的赋值与复制行为](#assignment_and_copy_behavior_for_collection_types)
|
||||
|
||||
类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照对于常量,变量以及函数所规定的语法规则来定义属性和添加方法。
|
||||
类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照常量、变量以及函数所规定的语法规则来定义属性和添加方法。
|
||||
|
||||
与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
Swift 中类和结构体有很多共同点。共同处在于:
|
||||
|
||||
* 定义属性用于储存值
|
||||
* 定义属性用于存储值
|
||||
* 定义方法用于提供功能
|
||||
* 定义附属脚本用于访问值
|
||||
* 定义构造器用于生成初始化值
|
||||
@ -75,9 +75,9 @@ class VideoMode {
|
||||
}
|
||||
```
|
||||
|
||||
在上面的示例中我们定义了一个名为`Resolution`的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为`width`和`height`的储存属性。储存属性是捆绑和储存在类或结构体中的常量或变量。当这两个属性被初始化为整数`0`的时候,它们会被推断为`Int`类型。
|
||||
在上面的示例中我们定义了一个名为`Resolution`的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为`width`和`height`的存储属性。存储属性是捆绑和存储在类或结构体中的常量或变量。当这两个属性被初始化为整数`0`的时候,它们会被推断为`Int`类型。
|
||||
|
||||
在上面的示例中我们还定义了一个名为`VideoMode`的类,用来描述一个视频显示器的特定模式。这个类包含了四个储存属性变量。第一个是`分辨率`,它被初始化为一个新的`Resolution`结构体的实例,具有`Resolution`的属性类型。新`VideoMode`实例同时还会初始化其它三个属性,它们分别是,初始值为`false`(意为“non-interlaced video”)的`interlaced`,回放帧率初始值为`0.0`的`frameRate`和值为可选`String`的`name`。`name`属性会被自动赋予一个默认值`nil`,意为“没有`name`值”,因它是一个可选类型。
|
||||
在上面的示例中我们还定义了一个名为`VideoMode`的类,用来描述一个视频显示器的特定模式。这个类包含了四个储存属性变量。第一个是`分辨率`,它被初始化为一个新的`Resolution`结构体的实例,具有`Resolution`的属性类型。新`VideoMode`实例同时还会初始化其它三个属性,它们分别是,初始值为`false`(意为“non-interlaced video”)的`interlaced`,回放帧率初始值为`0.0`的`frameRate`和值为可选`String`的`name`。`name`属性会被自动赋予一个默认值`nil`,意为“没有`name`值”,因为它是一个可选类型。
|
||||
|
||||
### 类和结构体实例
|
||||
|
||||
@ -94,7 +94,7 @@ let someVideoMode = VideoMode()
|
||||
|
||||
### 属性访问
|
||||
|
||||
通过使用*点语法*(*dot syntax*),你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接:
|
||||
通过使用*点语法*(*dot syntax*),你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接:
|
||||
|
||||
```swift
|
||||
println("The width of someResolution is \(someResolution.width)")
|
||||
@ -171,7 +171,7 @@ println("hd is still \(hd.width ) pixels wide")
|
||||
// 输出 "hd is still 1920 pixels wide"
|
||||
```
|
||||
|
||||
在将`hd`赋予给`cinema`的时候,实际上是将`hd`中所储存的`值(values)`进行拷贝,然后将拷贝的数据储存到新的`cinema`实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将`cinema`的`width`修改为`2048`并不会影响`hd`中的宽(width)。
|
||||
在将`hd`赋予给`cinema`的时候,实际上是将`hd`中所存储的`值(values)`进行拷贝,然后将拷贝的数据存储到新的`cinema`实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将`cinema`的`width`修改为`2048`并不会影响`hd`中的宽(width)。
|
||||
|
||||
枚举也遵循相同的行为准则:
|
||||
|
||||
@ -193,7 +193,7 @@ if rememberDirection == .West {
|
||||
<a name="classes_are_reference_types"></a>
|
||||
## 类是引用类型
|
||||
|
||||
与值类型不同,引用类型在被赋予到一个变量,常量或者被传递到一个函数时,操作的并不是其拷贝。因此,引用的是已存在的实例本身而不是其拷贝。
|
||||
与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,操作的是引用,其并不是拷贝。因此,引用的是已存在的实例本身而不是其拷贝。
|
||||
|
||||
请看下面这个示例,其使用了之前定义的`VideoMode`类:
|
||||
|
||||
@ -214,7 +214,7 @@ let alsoTenEighty = tenEighty
|
||||
alsoTenEighty.frameRate = 30.0
|
||||
```
|
||||
|
||||
因为类是引用类型,所以`tenEight`和`alsoTenEight`实际上引用的是相同的`VideoMode`实例。换句话说,它们只是同一个实例的两种叫法。
|
||||
因为类是引用类型,所以`tenEight`和`alsoTenEight`实际上引用的是相同的`VideoMode`实例。换句话说,它们是同一个实例的两种叫法。
|
||||
|
||||
下面,通过查看`tenEighty`的`frameRate`属性,我们会发现它正确的显示了基本`VideoMode`实例的新帧率,其值为`30.0`:
|
||||
|
||||
@ -223,11 +223,11 @@ println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
|
||||
// 输出 "The frameRate property of theEighty is now 30.0"
|
||||
```
|
||||
|
||||
需要注意的是`tenEighty`和`alsoTenEighty`被声明为*常量((constants)*而不是变量。然而你依然可以改变`tenEighty.frameRate`和`alsoTenEighty.frameRate`,因为这两个常量本身不会改变。它们并不`储存`这个`VideoMode`实例,在后台仅仅是对`VideoMode`实例的引用。所以,改变的是被引用的基础`VideoMode`的`frameRate`参数,而不改变常量的值。
|
||||
需要注意的是`tenEighty`和`alsoTenEighty`被声明为*常量((constants)*而不是变量。然而你依然可以改变`tenEighty.frameRate`和`alsoTenEighty.frameRate`,因为这两个常量本身不会改变。它们并不`存储`这个`VideoMode`实例,在后台仅仅是对`VideoMode`实例的引用。所以,改变的是被引用的基础`VideoMode`的`frameRate`参数,而不改变常量的值。
|
||||
|
||||
### 恒等运算符
|
||||
|
||||
因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。(对于结构体和枚举来说,这并不成立。因为它们作值类型,在被赋予到常量,变量或者传递到函数时,总是会被拷贝。)
|
||||
因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。(对于结构体和枚举来说,这并不成立。因为它们作为值类型,在被赋予到常量、变量或者传递到函数时,其值总是会被拷贝。)
|
||||
|
||||
如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符:
|
||||
|
||||
@ -243,7 +243,7 @@ if tenEighty === alsoTenTighty {
|
||||
//输出 "tenEighty and alsoTenEighty refer to the same Resolution instance."
|
||||
```
|
||||
|
||||
请注意“等价于”(用三个等号表示,===) 与“等于”(用两个等号表示,==)的不同:
|
||||
请注意```“等价于"```(用三个等号表示,===) 与```“等于"```(用两个等号表示,==)的不同:
|
||||
|
||||
* “等价于”表示两个类类型(class type)的常量或者变量引用同一个类实例。
|
||||
* “等于”表示两个实例的值“相等”或“相同”,判定时要遵照类设计者定义定义的评判标准,因此相比于“相等”,这是一种更加合适的叫法。
|
||||
@ -259,7 +259,7 @@ if tenEighty === alsoTenTighty {
|
||||
|
||||
在你的代码中,你可以使用类和结构体来定义你的自定义数据类型。
|
||||
|
||||
然而,结构体实例总是通过值传递,类实例总是通过引用传递。这意味两者适用不同的任务。当你的在考虑一个工程项目的数据构造和功能的时候,你需要决定每个数据构造是定义成类还是结构体。
|
||||
然而,结构体实例总是通过值传递,类实例总是通过引用传递。这意味两者适用不同的任务。当你在考虑一个工程项目的数据构造和功能的时候,你需要决定每个数据构造是定义成类还是结构体。
|
||||
|
||||
按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
|
||||
|
||||
@ -421,7 +421,7 @@ if b[0...1] === b[0...1] {
|
||||
|
||||
### 强制复制数组
|
||||
|
||||
我们通过调用数组的`copy`方法进行强制显性复制。这个方法对数组进行了浅拷贝(shallow copy),并且返回一个包含此拷贝的新数组。
|
||||
我们通过调用数组的`copy`方法进行强制显式复制。这个方法对数组进行了浅拷贝(shallow copy),并且返回一个包含此拷贝数组的新数组。
|
||||
|
||||
下面这个示例中定义了一个`names`数组,其包含了七个人名。还定义了一个`copiedNames`变量,用以储存在`names`上调用`copy`方法所返回的结果:
|
||||
|
||||
@ -430,7 +430,7 @@ var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
|
||||
var copiedNames = names.copy()
|
||||
```
|
||||
|
||||
我们可以通过修改一个数组中某元素,并且检查另一个数组中对应元素的方法来判定`names`数组确已被复制。如果你将`copiedNames`中第一个元素从"`Mohsen`"修改为"`Mo`",则`names`数组返回的仍是拷贝发生前的"`Mohsen`":
|
||||
我们可以通过修改数组中某一个元素,并且检查另一个数组中对应元素的方法来判定`names`数组确已被复制。如果你将`copiedNames`中第一个元素从"`Mohsen`"修改为"`Mo`",则`names`数组返回的仍是拷贝发生前的"`Mohsen`":
|
||||
|
||||
```swift
|
||||
copiedName[0] = "Mo"
|
||||
|
||||
Reference in New Issue
Block a user