作為Swift中的另外一種自定義類型诬像,從語法上來說,class和struct有很多相似的地方闸婴,例如:
struct PointValue {
var x: Int
var y: Int
}
class PointRef {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
可以看到坏挠,它們都可以用來自定義類型、都可以有properties邪乍,也都可以有methods降狠。因此对竣,單純從語法上來理解class是個沒什么意義的事情。在之前我們也說過榜配,作為Swift中的引用類型否纬,class表達(dá)的是一個具有明確生命周期的對象,我們需要關(guān)注這類內(nèi)容的“生死存亡”蛋褥,而值類型烦味,我們更多關(guān)注的,就真的只是它的值而已壁拉。
引用類型必須明確指明 init
方法
首先谬俄,Swift并不會為class自動生成默認(rèn)的init方法。如果我們不定義它弃理,Swift編譯器會報錯溃论。因此,無論多么簡單的class痘昌,我們至少要為它定義一個初始化其所有屬性的init方法钥勋。
為什么要如此呢?前面提到了辆苔,class并不簡單表達(dá)一個“值”的概念算灸。Swift要求我們明確通過init
方法說明“打造”一個對象的過程。相反驻啤,struct表達(dá)一個自定義的“值”菲驴,在沒有特別說明的情況下,一個值的初始化當(dāng)然是把它的每一個member
都按順序初始化骑冗。
引用類型關(guān)注的是對象本身
其次赊瞬,class和struct對“常量”的理解是不同的。我們分別定義一個PointRef和PointValue的常量:
let p1 = PointRef(x: 0, y: 0)
let p2 = PointValue(x: 0, y: 0)
同樣是常量贼涩,當(dāng)我們修改p2的屬性時巧涧,編譯器會報錯:p2 is a let constant。但是我們卻可以修改 p1 遥倦,這是因?yàn)?p2 是一個值類型谤绳,常量的意義在于它的值不能被改變。但是 p1 是一個引用類型袒哥,這時候這個常量的意義則變成了:它可以修改自身的屬性缩筛,但不能再引用其他的對象。
除了這種語義上面的差別统诺,我們還可以看到如果我們進(jìn)行賦值操作歪脏,也會有差別
var p3 = p1
var p4 = p2
這個時候 如果我們修改 p3 的屬性那么 p1 的屬性也會一起被修改,但是當(dāng)我們修改 p4 的時候粮呢, p2 卻并沒有被修改。
引用類型默認(rèn)是可以修改屬性的,這是因?yàn)橐妙愋完P(guān)注的是其引用的對象而啄寡,不是對象的值豪硅。
值類型卻是默認(rèn)情況下不允許修改屬性的。如果你在寫接口的時候挺物,沒有用mutating
來修飾你的方法懒浮,那么使用你接口的人就要抓狂了。他無法對你的屬性進(jìn)行操作识藤。(值類型的賦值操作就是基本的內(nèi)存拷貝砚著,因此你可以直接使用self
進(jìn)行賦值操作,編譯器會自動將每一個屬性值設(shè)置到self
對應(yīng)的屬性痴昧。然而在引用類型中稽穆,self
是一個常量,不能在引用其它對象)