Structure 和Class 的差别
相同之处
1.拥有自己的属性(property)及方法(function)
2.可以自订建构子(initializer)
不同之处
- Structure无法继承
- Structure拥有成员建构子(Memberwise Initializer)
- Structure是Value Type , Class是Reference Type
- Structure不能直接修改内部属性,如果要修改必须加上mutating
大致意思就是说,虽然结构体和枚举可以定义自己的方法,但是默认情况下,实例方法中是不可以修改值类型的属性。
举个简单的例子,假如定义一个点结构体,该结构体有一个修改点位置的实例方法:
struct Point {
var x = 0, y = 0
func moveXBy(x:Int,yBy y:Int) {
self.x += x
// Cannot invoke '+=' with an argument list of type '(Int, Int)'
self.y += y
// Cannot invoke '+=' with an argument list of type '(Int, Int)'
}
}
编译器抛出错误,说明确实不能在实例方法中修改属性值。
为了能够在实例方法中修改属性值,可以在方法定义前添加关键字 mutating
struct Point {
var x = 0, y = 0
mutating func moveXBy(x:Int,yBy y:Int) {
self.x += x
self.y += y
}
}
var p = Point(x: 5, y: 5)
p.moveXBy(3, yBy: 3)
另外,在值类型的实例方法中,也可以直接修改self属性值。
enum TriStateSwitch {
case Off, Low, High
mutating func next() {
switch self {
case Off:
self = Low
case Low:
self = High
case High:
self = Off
}
}
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight is now equal to .High
ovenLight.next()
// ovenLight is now equal to .Off”
TriStateSwitch枚举定义了一个三个状态的开关,在next实例方法中动态改变self属性的值。
当然,在引用类型中(即class)中的方法默认情况下就可以修改属性值,不存在以上问题。
7. 值类型和引用类型的区别
由于 Swift 中的 struct 为值类型,class 为引用类型,因此文中以这两种类型为代表来具体阐述
stack & heap
内存(RAM)中有两个区域,栈区(stack)和堆区(heap)。在 Swift 中,值类型,存放在栈区;引用类型,存放在堆区。
class RectClass {
var height = 0.0
var width = 0.0
}
struct RectStruct {
var height = 0.0
var width = 0.0
}
var rectCls = RectClass()
var rectStrct = RectStruct()
值类型(Value Type)
值类型,即每个实例保持一份数据拷贝。
在 Swift 中,典型的有 struct
,enum
,以及 tuple
都是值类型。而平时使用的 Int
, Double
,Float
,String
,Array
,Dictionary
,Set
其实都是用结构体实现的,也是值类型。
Swift 中,值类型的赋值为深拷贝(Deep Copy),值语义(Value Semantics)即新对象和源对象是独立的,当改变新对象的属性,源对象不会受到影响,反之同理。
在 Swift 中,双等号(==
&!=
)可以用来比较变量存储的内容是否一致,如果要让我们的struct
类型支持该符号,则必须遵守 Equatable
协议。
extension CoordinateStruct: Equatable {
static func ==(left: CoordinateStruct, right: CoordinateStruct) -> Bool {
return (left.x == right.x && left.y == right.y)
}
}
if coordA != coordB {
print("coordA != coordB")
}
引用类型(Reference Type)
引用类型,即所有实例共享一份数据拷贝。
在 Swift 中,class 和闭包是引用类型。引用类型的赋值是浅拷贝(Shallow Copy),引用语义(Reference Semantics)即新对象和源对象的变量名不同,但其引用(指向的内存空间)是一样的,因此当使用新对象操作其内部数据时,源对象的内部数据也会受到影响。
class Dog {
var height = 0.0
var weight = 0.0
}
var dogA = Dog()
var dogB = dogA
dogA.height = 50.0
print("dogA.height -> \(dogA.height)")
print("dogB.height -> \(dogB.height)")
// dogA.height -> 50.0
// dogB.height -> 50.0
如果声明一个引用类型的常量,那么就意味着该常量的引用不能改变(即不能被同类型变量赋值),但指向的内存中所存储的变量是可以改变的。
在 Swift 中,三等号(===
&!==
)可以用来比较引用类型的引用(即指向的内存地址)是否一致。也可以在遵守 Equatable
协议后,使用双等号(==
&!=
)用来比较变量的内容是否一致。
函数传参
在 Swift 中,函数的参数默认为常量,即在函数体内只能访问参数,而不能修改参数值。具体来说:
1.值类型作为参数传入时,函数体内部不能修改其值
2.引用类型作为参数传入时,函数体内部不能修改其指向的内存地址,但是可以修改其内部的变量值