- [值類型和引用類型]
- [什么是值類型(value type)和引用類型(reference type)]
- [兩者有什么不同]
- [請在保證安全的情況下修改變量值]
- [如何選擇]
- [c++類型行為的不一致性]
- [ 參考文章]
變量類型可以幫助開發(fā)者理清程序的數(shù)據(jù)流酣胀,以寫出更健壯的代碼城丧。本文通過對swift語言中的兩種變量類型的介紹垒在,來說明哪些情況下適合使用value/reference type拯杠。閱讀本文不需要對swift有深入了解碎捺,當然熟悉swift編程對理解本文會有幫助萝招。
什么是值類型(value type)和引用類型(reference type)
在swift中袜腥,一個類型要么是value type茬贵, 要么是reference type郊霎。value type指每一個變量在內存中都有單獨的一份數(shù)據(jù)拷貝沼头。reference type指數(shù)據(jù)在內存中只有一份拷貝,多個變量共享它的值书劝。和c++中類型的使用方式不同进倍,swift中類型的屬性(value/reference)是由類型本身決定的,作為語言標準給出购对,稍后本文會再做介紹猾昆。
比如c++中,
#include <iostream>
int main() {
int a = 1;
int &b = a; //c++中的引用可以使用在所有的類型上
b = 2;
printf("a = %d, b = %d\n", a, b); //輸出結果為:a = 2, b = 2
}
兩者有什么不同
辨別value type骡苞,最基本和最有效的方法是觀察它的拷貝行為--賦值垂蜗、初始化、參數(shù)傳遞等帶來的影響解幽,即通過內存數(shù)據(jù)拷貝 創(chuàng)建 一個獨立的實例(instance)贴见。
// Value type example
struct S { var data: Int = -1 }
var a = S()
var b = a // a is copied to b
a.data = 42 // Changes a, not b
println("\(a.data), \(b.data)") // prints "42, -1"
拷貝引用則不同,它的行為類似于創(chuàng)建了一個指針躲株,原來在內存中的數(shù)據(jù)依然保持一份拷貝片部。因而改變其中某一個變量的值也會影響其他變量,即產(chǎn)生副作用徘溢。
// Reference type example
class C { var data: Int = -1 }
var x = C() // 建立一個對象的引用x
var y = x // 建立對象的另一個引用y
x.data = 42 // changes the instance referred to by x (and y)
println("\(x.data), \(y.data)") // prints "42, 42"
可以看出這個例子和之前c++引用產(chǎn)生了同樣的效果吞琐。
請在保證安全的情況下修改變量值
開發(fā)軟件捆探,其中最重要的要求(之一)是程序的正確性然爆,一種保證是來自于編程語言本身,另一種當然是來自程序員黍图。那么程序員在寫代碼的過程中如何選擇使用的類型呢曾雕?value type和reference type相比較,選擇使用value type可以使你的程序直觀上更加符合邏輯助被。如果所有的變量在內存中都有自己單獨的一塊區(qū)域剖张,你就大可不必擔心程序的其他部分在無意中修改這些變量的值。這在多線程環(huán)境中尤其重要揩环,因為不同的線程會同時修改變量的值搔弄。如果變量是reference類型就十分危險,這使你的程序出現(xiàn)不可預期的結果丰滑,調試起來也非常困難顾犹。
更理想的一種情況是,你聲明和使用的變量是只讀(不可寫)的,就不會出現(xiàn)數(shù)據(jù)不一致的情況發(fā)生炫刷。實際上擎宝,在沒有變量值改動的程序中,變量是type的或者reference的對程序的行為沒有任何影響浑玛。這時候reference內存占用少绍申,當然是優(yōu)先使用reference。
如何選擇
使用value type顾彰,當:
- 你想要變量之間的賦值隱含數(shù)據(jù)拷貝极阅,使變量之間的狀態(tài)完全獨立。
- 代碼中的數(shù)據(jù)操作分布在多個進程拘央。
使用reference type涂屁,當:
- 創(chuàng)建共享和允許修改的狀態(tài)。
很多人其實有一種對編程語言的誤解灰伟,認為在語言層面約束越少的語言越好拆又,這樣就可以很容易實現(xiàn)想要的功能。但是靈活性帶來的壞處更加容易被人忽視栏账。交給程序員處理的事情越多帖族,導致寫出來的代碼更加容易產(chǎn)生bug,代碼可閱讀性大大降低挡爵,同時增加重構的難度竖般。
而swift在這方面給出了比較嚴格的限制,在swift中茶鹃,struct
, Array
, String
, 和 Dictionary
都是value type涣雕,它們的行為就像c語言中的int
,你幾乎不用做任何額外的工作闭翩,比如為了防止代碼的其余部分對數(shù)據(jù)進行修改而顯式地為變量分配額外的內存空間挣郭,這些繁瑣的過程都會因為swift中變量的value type的屬性,而交給編譯器去做疗韵。更加重要的是兑障,你可以很放心的將變量的數(shù)據(jù)拷貝交給其他進程進行操作而不用擔心同步問題。這些語言層面的約束都是為了程序員可以寫出可預測的代碼蕉汪。作為對比流译,下文介紹c++是怎么做的。
c++類型行為的不一致性
碰巧在微信中看到的一篇文章:C++ 之 stl::string 寫時拷貝導致的問題者疤。c++在語言標準上允許不同的數(shù)據(jù)拷貝機制福澡,聯(lián)系到本文的概念,即c++中的類型是value type還是reference type取決于編譯器的實現(xiàn)驹马。當語言標準容忍實現(xiàn)的靈活性時革砸,雖然多數(shù)時候是為了優(yōu)化性能眯搭,但是帶來的問題似乎更加嚴重--導致程序的運行結果不同于預期。