Swift 类和结构体总结
类和结构体都是多功能而且灵活的结构,它们可以作为构建块(building block)在代码中使用。你可以为类和结构体定义属性和方法来扩充它们的功能。对于自定义类,Swift不需要你创建单独的接口和文件来实现类和接口,你在一个文件中定义和实现类和结构体即可。
类和结构体的比较
类和结构体有很多相似之处:
• 定义存储值的属性
• 定义方法提供功能
• 定义下标,通过下标语法访问元素的值
• 定义初始化器来初始化状态
• 可以服从特定的协议提供标准功能
类还有一些结构体没有的功能:
• 继承使得一个类能够继承其他类的属性
• 类型转化能够让你在运行时检查和解释类实例的类型
• 类的解析(Deinitializer)能够释放类实例分配到的任何资源
• 引用计数允许一个类实例有一个或者多个引用
类和结构体定义
相比于C语言,Swift 的结构体强大了很多,可以有方法,构造方法等。使用struct关键字来定义一个结构体,使用class关键字来定义一个类,定义的主体位于一个花括号中。语法:
struct structName {
var varity: Type1
var varity1: Type2
}
class SomeClass{
//class definition goes here
}
如:
struct Rect{
var height: Double
var width: Double
}
struct Resolution{
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
结构体和类的定义中,由于创建了新的类型,所以类和结构体的名称采用首字母大写的驼峰标识,而属性和方法则采用首字母小写的驼峰标识。
类和结构体实例
类和结构体的定义仅仅是提供了一个模板,说明这些实例应该长这样子的。比如Resolution提供了一个分辨率的模板,而VideoMode则提供了一个视频模式的模板。如果要使用类和结构体,则还需要实例化类和结构体产生实例。类和结构体实例化的语法都非常类似:
let someResolutio = Resolution()
let someVideoMode = VideoMode()
这是最简单的实例化方式,使用类或结构体的名字外加一个括号即可。
访问属性
我们采用“.”来访问实例的属性。如下面所示:
struct Rect{
var height: Double = 0.0
var width: Double = 0.0
}
//实例化:
var rect: Rect = Rect()
rect.height = 10.0
rect.width = 20.0 //为实例变量赋值
跟Objective-C不一样,Swift可以让你直接访问属性的属性,如上面的VideoMode
这个类有一个结构体实例,可以直接访问这个实例的属性。
someVideoMode.resolution.height = 960
someVideoMode.resolution.width = 1280
结构体的构造器
构造器的作用不是分配内存,而是系统给分配内存之后,自动调用构造器方法,进行初始化内存,初始化成员变量。所以,构造器主要分两种,一种是构造结构体时指定所有成员变量的初始值,此时不用带参数,如 var rect: Rect = Rect()
;第二种是逐一成员构造器,因为成员变量在构造结构体的时候没有初始化,如:
struct Rect{
var height: Double
var width: Double
}
var rect = Rect(height: 10.0, width: 20.0) //注意,height和width的顺序不能调换
结构体和枚举类型是值类型
值类型意味着在给一个变量或者常量赋值或者传递给函数的时候采用的是拷贝的方式。在以前所接触到的类型Int、Float、Double、Bool、String、Array、Dictionary
等都是值类型。在Swift中所有的结构体和枚举类型都是结构体。可以看看以下示例:
var highResolution = Resolution(width: 1920, height: 1080)
var cinema = highResolution
//改变cinema的一个的属性
cinema.width = 2048
//highResolution 的属性并没有改变,所以是值传递
print("highResolution: (width: \(highResolution.width), height: \(highResolution.height))")
输出结果为:
highResolution: (width: 1920, height: 1080)
Program ended with exit code: 0
enum CompassPoint {
case north, south, east, west
}
var currentDirection = CompassPoint.east
var anotherDirection = currentDirection
anotherDirection = .west
if(currentDirection == .east){
print("current direction is still east")
}
输出结果为:
current direction is still east
Program ended with exit code: 0
说明枚举类型的赋值也是值传递,采用的是拷贝方式。
类是引用类型
引用类型是当赋值给变量或者常量或者传递给函数时不会采用值拷贝,而是采用引用传递的方式,多个变量或者常量指向同一个实例。
let tenEighty = VideoMode()
tenEighty.resolution = highResolution
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("the frame rate of the tenEighty is \(tenEighty.frameRate)")
输出结果为:
the frame rate of the tenEighty is 30.0
Program ended with exit code: 0
说明tenEighty
和alsoTenEighty
指向的是同一个实例,所以是引用传递。
相等操作符
因为类是引用类型,所以存在着多个常量或者变量指向同一个实例,那么如何判断它们是否指向同一变量呢?使用相等操作符 ===,这是连续三个等号组成的操作符。
如果指向同一个实例,则是===,否则为!==
注意,该符号只能用于类的实例,不能用于结构体和其他值类型。
类和结构体之间的抉择
你可以使用类和结构体来自定义类型,在代码中将其视为构建块来使用。但是结构体实例是传值,而类实例是传引用。那么如何在二者之间抉择呢?这里有一个一般性的准则。当应用到以下条件时可以考虑创建结构体:
• 结构体的主要目的是封装一些简单的相关数据值
• 当赋值或者传递时希望这些封装的值将会被拷贝而不是引用
• 由结构体存储的值都值类型,它们更多是的是拷贝而不是引用
• 结构体不需要从其他类型继承属性
比如以下示例:
• 几何图形的尺寸
• 三维坐标的点
.......
其他情况下都可以考虑使用类。实际情况上,这就意味着大多数的自定义类型是类,而不是结构体。