Structure 和Class 的差別
相同之處
1.擁有自己的屬性(property)及方法(function)
2.可以自訂建構(gòu)子(initializer)
不同之處
- Structure無法繼承
- Structure擁有成員建構(gòu)子(Memberwise Initializer)
- Structure是Value Type , Class是Reference Type
- Structure不能直接修改內(nèi)部屬性,如果要修改必須加上mutating
大致意思就是說圆恤,雖然結(jié)構(gòu)體和枚舉可以定義自己的方法蚤霞,但是默認情況下茸苇,實例方法中是不可以修改值類型的屬性胁住。
舉個簡單的例子筹吐,假如定義一個點結(jié)構(gòu)體,該結(jié)構(gòu)體有一個修改點位置的實例方法:
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)'
}
}
編譯器拋出錯誤狮崩,說明確實不能在實例方法中修改屬性值蛛勉。
為了能夠在實例方法中修改屬性值,可以在方法定義前添加關(guān)鍵字 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枚舉定義了一個三個狀態(tài)的開關(guān)坦敌,在next實例方法中動態(tài)改變self屬性的值侣诵。
當然,在引用類型中(即class)中的方法默認情況下就可以修改屬性值狱窘,不存在以上問題杜顺。
7. 值類型和引用類型的區(qū)別
由于 Swift 中的 struct 為值類型,class 為引用類型训柴,因此文中以這兩種類型為代表來具體闡述
stack & heap
內(nèi)存(RAM)中有兩個區(qū)域哑舒,棧區(qū)(stack)和堆區(qū)(heap)妇拯。在 Swift 中幻馁,值類型洗鸵,存放在棧區(qū);引用類型仗嗦,存放在堆區(qū)膘滨。
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)
值類型,即每個實例保持一份數(shù)據(jù)拷貝稀拐。
在 Swift 中火邓,典型的有 struct
,enum
德撬,以及 tuple
都是值類型铲咨。而平時使用的 Int
, Double
蜓洪,Float
纤勒,String
,Array
隆檀,Dictionary
摇天,Set
其實都是用結(jié)構(gòu)體實現(xiàn)的,也是值類型恐仑。
Swift 中泉坐,值類型的賦值為深拷貝(Deep Copy),值語義(Value Semantics)即新對象和源對象是獨立的裳仆,當改變新對象的屬性腕让,源對象不會受到影響,反之同理鉴逞。
在 Swift 中,雙等號(==
&!=
)可以用來比較變量存儲的內(nèi)容是否一致,如果要讓我們的struct
類型支持該符號滑凉,則必須遵守 Equatable
協(xié)議畅姊。
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)
引用類型若未,即所有實例共享一份數(shù)據(jù)拷貝倾鲫。
在 Swift 中萍嬉,class 和閉包是引用類型隙疚。引用類型的賦值是淺拷貝(Shallow Copy),引用語義(Reference Semantics)即新對象和源對象的變量名不同,但其引用(指向的內(nèi)存空間)是一樣的悼做,因此當使用新對象操作其內(nèi)部數(shù)據(jù)時贿堰,源對象的內(nèi)部數(shù)據(jù)也會受到影響。
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
如果聲明一個引用類型的常量庶灿,那么就意味著該常量的引用不能改變(即不能被同類型變量賦值)纵搁,但指向的內(nèi)存中所存儲的變量是可以改變的腾誉。
在 Swift 中瘦癌,三等號(===
&!==
)可以用來比較引用類型的引用(即指向的內(nèi)存地址)是否一致热押。也可以在遵守 Equatable
協(xié)議后桶癣,使用雙等號(==
&!=
)用來比較變量的內(nèi)容是否一致。
函數(shù)傳參
在 Swift 中尤慰,函數(shù)的參數(shù)默認為常量,即在函數(shù)體內(nèi)只能訪問參數(shù)匪煌,而不能修改參數(shù)值。具體來說:
1.值類型作為參數(shù)傳入時,函數(shù)體內(nèi)部不能修改其值
2.引用類型作為參數(shù)傳入時,函數(shù)體內(nèi)部不能修改其指向的內(nèi)存地址刀森,但是可以修改其內(nèi)部的變量值