与其他编程语言不用的是,Swift并不要求你为自定义的结构体和类的接口与实现代码分别创建文件。你只需在单一的文件中定义一个结构体或者类,系统将会自动生成面向其他代码的外部接口。
1、结构体和类对比
Swift中结构体和类有很多共同点。两者都可以:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义下标操作用于通过下标语法访问它们的值
- 定义构造器用于设置初始值
- 通过扩展以增加默认实现之外的功能
- 遵循协议以提供某种标准功能
与结构体相比,类还有如下的附加功能:
- 继承允许一个类继承另一个类的特征
- 类型转换允许在运行时检查和解释一个类实例的类型
- 析构器允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用
类支持的附加功能是以增加复杂性为代价的,作为一般准则,优先使用结构体。
(1)类型定义的语法
struct
关键字引入结构体,class
关键字引入类:
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
(2)结构体和类的实例
结构体和类都使用构造器语法来创建新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随 ()
。通过这种方式所创建的类或者结构体实例,其属性均会被初始化为默认值。
let someResolution = Resolution()
let someVideoMode = VideoMode()
(3)属性访问
- 可以使用点语法访问实例的属性:
print("The width of someResolution is \(someResolution.width)")
// 打印 "The width of someResolution is 0"
- 可以访问子属性,如
VideoMode
中resolution
属性的width
属性:
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// 打印 "The width of someVideoMode is 0"
- 可以使用点语法为可变属性赋值:
someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// 打印 "The width of someVideoMode is now 1280"
(4)结构体类型的成员逐一构造器
所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中:
let vga = Resolution(width: 640, height: 480)
注意:与结构体不同,类实例没有默认的成员逐一构造器。
2、结构体和枚举是值类型
值类型是这样一种类型,当它被赋值给一个变量、常量或者被传递给一个函数时,其值会被拷贝。
Swift中所有的基本类型:整型、浮点数、布尔值、字符串、数组和字典,都是值类型,其底层也是使用结构体实现的。
Swift中所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型的属性,在代码中传递的时候都会被复制。
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
print("cinema is now \(cinema.width) pixels wide")
// 打印 "cinema is now 2048 pixels wide"
print("hd is still \(hd.width) pixels wide")
// 打印 "hd is still 1920 pixels wide"
枚举也遵循相同的行为准则:
enum CompassPoint {
case north, south, east, west
mutating func turnNorth() {
self = .north
}
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()
print("The current direction is \(currentDirection)")
print("The remembered direction is \(rememberedDirection)")
// 打印 "The current direction is north"
// 打印 "The remembered direction is west"
注意:标准库定义的集合,例如数组、字典和字符串,都对复制进行了优化以降低性能成本。新集合不会立即复制,而是跟原集合共享同一份内存,共享同样的元素。在集合的某个副本要被修改前,才会复制它的元素。
3、类是引用类型
与值类型不同,引用类型在被赋值到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,使用的是已存在实例的引用,而不是其拷贝。
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// 打印 "The frameRate property of theEighty is now 30.0"
注意:
tenEighty
和alseTenEighty
被声明为常量而不是变量,但是依然可以改变tenEighty.frameRate
和alsoTenEighty.frameRate
,这是因为tenEighty
和alsoTenEighty
这两个常量的值并未改变。它们并不“存储”这个VideoMode
实例,而仅仅是对VideoMode
实例的引用。所以,改变的是底层VideoMode
实例的frameRate
属性,而不是指向VideoMode
的常量引用的值。
(1)恒等运算符
判定两个常量或者变量是否引用同一个类实例,可以用恒等运算符:
- 相同 (
===
) - 不相同 (
!==
)
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// 打印 "tenEighty and alsoTenEighty refer to the same VideoMode instance."
(2)指针
Swift 中引用了某个引用类型实例的常量或变量,与 C 语言中的指针类似,不过它并不直接指向某个内存地址,也不要求你使用星号(*
)来表明你在创建一个引用。相反,Swift 中引用的定义方式与其它的常量或变量的一样
网友评论