變量賦值有兩種方式:按值傳遞、按"指針"傳遞(指針也常稱爲"引用")。不一樣的編程語言賦值的方式不同,例如Python是按"指針"傳遞的,Go是按值傳遞的。python
注意,"指針"加了引號,由於它不是真正的按指針拷貝,見下文分析。編程
參數傳值其實也是變量賦值的過程,只不過參數是函數的本地變量而已。數組
按值傳遞的意思是每次賦值都拷貝內存中完整的數據結構對象,這時在內存中會保存兩分內容徹底相同,但地址不一樣的數據對象。數據結構
按"指針"傳遞的意思是每次賦值都只拷貝內存中數據結構對象的地址,這個地址佔用一個機器字長(一個機器字長,在32位cpu上爲32bit共4字節,64位則64bit共8字節),固然有些數據結構除了指針還包括其它屬性,這時可能會佔用數個機器字長。總之,按"指針"傳遞時,因爲只拷貝一份能表示數據對象的屬性(好比地址),拷貝的內容很是少,速度很是快。但必須注意,拷貝"指針"後,內存中只有一份數據對象,但將有兩份徹底相同的指向內存中數據對象的"指針",不管是經過哪一個"指針"去修改數據對象,都會影響另外一個。編程語言
對於那些不支持操做指針的語言,一般會將按"指針"傳遞稱爲"淺拷貝(shallow copy)",而後額外提供一個函數或工具實現按指傳遞,這稱爲"深拷貝(deep copy)"。函數
例如:工具
a=10 b=a
首先會在內存中劃分一個格子用來建立數據對象10,而後將這個數據對象的地址保存到變量a中。指針
若是是按值拷貝的語言,則會在內存中拷貝一份數據對象10的副本,再將這個副本數據對象的地址保存到b中。code
顯然,a和b保存的地址是不同的,內存中也有兩分內容徹底相同的數據對象10。因此,修改a的值時不會影響b的值,修改b的值時不會影響a。對象
若是是按"指針"拷貝的語言,則會直接拷貝a中的地址並保存到b中。
由於a和b的地址都同樣,因此,修改a的值會影響b,修改b的值會影響a。
也許你已經發現了,按"指針"傳遞時,雖然a、b保存的地址相同,但若是a=11
,a將指向新的數據對象,而b仍然指向10,即b=10
,修改a並無影響b。這是由於數值是不可變的,沒法在原始的內存地址處修改,也就是沒法將10替換成11,因此只要想修改這種不可變的對象就必定會建立新數據對象。對此,有兩方面須要說明。
一方面,有些數據對象是能夠在原始內存地址處直接進行替換修改的(例如python中的列表)。假設,某編程語言對數值也是可原處修改的,那麼a=11
將會在內存中將10替換成11,而不會新建立另外一個數據對象11。
另外一方面,上面的"按指針傳遞"並不是是真正的按指針傳遞,而是按引用傳遞,或者說是按地址傳遞。這就是前文"按指針傳遞"中的"指針"都加上了引號的緣由。
真正的指針是額外保存的,是佔用空間的,和變量不一樣(變量保存了地址,在棧空間中),它是保存在堆內存中的。對於支持指針操做的語言(如C、C++、Go等),須要使用語法獨立生成數據對象的指針,這類語言通常都能直接在原處修改數據對象。例如:
a=10 b=&a
其中b=&a
表示生成a所指向(由於a保存了地址)數據對象的一個額外的指針,這個指針中保存了數據對象的地址,而後將這個指針賦值給b,這時b保存的是指針的地址,而不是數據對象的地址。
這時,修改a,或者修改b都會影響另外一方,由於支持指針操做的語言通常都支持原處修改:
a=11 print(*b) /* 輸出11 */
其中*b
表示解除指針的引用,也就是取得數據對象的內容。
再回到按"指針"傳遞的拷貝方式,雖然它不是真正的拷貝指針,而是拷貝地址,但對於那些支持原處修改的數據對象,它們達到的效果和真實的指針傳遞是同樣的。例如,數組、python的列表。
# 如下爲python代碼: L1=[1,2,3,4] L2=L1 L2[0]=11 print(L1) # 輸出:[11,2,3,4]
支持指針操做的語言,經過指針修改數據時,是直接在原始地址塊上修改成新數據的。例如:
func main() { a := 10 println(a) println(&a) println("---------------") *(&a) = 20 println(a) println(&a) }
結果:
10 0xc042085f48 --------------- 20 0xc042085f48
可是python中的可變對象(好比列表),雖然俗稱"原處修改",但並不是真的原處修改,而是在堆內存中新建立一個數據對象,並將它做爲可變對象的一部分,因此可變對象總體的地址沒有改變,但內部元素的地址已經改變了,也就是舊的元素對象被回收。
>>> L=[222,333,444,555] >>> id(L),id(L[1]) (44652184, 43798256) >>> L[1]=3333 >>> id(L),id(L[1]) (44652184, 43798240)