Goland的值與引用類型

Goland的值與引用類型

在新的項目中,用到的Goland。以前用Python做項目,Python基本變量的賦值是引用重定向。Goland有些不一樣,這裏做個測試

直接利用打印變量值、地址的方式確認變量拷貝情況

package main
import "fmt"

func getInt() int {
	i := 5
	println("in getInt, i", i, &i)
	return i
}

func intTest(i int) {
	println("in intTest, i", i, &i)
	i = 99
}

func listTest(list []int) {
	println("in listTest, list", &list, list)
	list[0] = 99
}

func mapTest(mapInt map[int]int) {
	println("in mapTest, mapInt", mapInt, &mapInt)
	mapInt[99] = 100
}

func main() {
	t := 1
	fmt.Println("in main, t", t, &t)
	t = 2
	fmt.Println("in main, t", t, &t)
	t = getInt()
	fmt.Println("in main, t", t, &t)
	intTest(t)
	fmt.Println("in main, t", t, &t)

	fmt.Println("*************************")
	l := []int{1,2,3}
	println("in main, l", &l, l)
	l = []int{1,2,3,4,5}
	println("in main, l", &l, l)

	l2 := l
	println("in main, l2", &l2, l2)
	listTest(l)
	fmt.Println("in main, l", l)

	fmt.Println("*************************")
	mapInt := make(map[int]int)
	mapInt[1] = 2
	println("in main, mapInt", mapInt, &mapInt)
	mapTest(mapInt)
	println("in main, mapInt", mapInt, &mapInt)
	fmt.Println("in main, mapInt", mapInt)
}

輸出結果
in main, t 1 0xc0000140a0
in main, t 2 0xc0000140a0
in getInt, i 5 0xc00006ade0
in main, t 5 0xc0000140a0
in intTest, i 5 0xc00006ade8
in main, t 5 0xc0000140a0
*************************
in main, l 0xc00006ae58 [3/3]0xc000012140
in main, l 0xc00006ae58 [5/5]0xc00001a060
in main, l2 0xc00006ae40 [5/5]0xc00001a060
in listTest, list 0xc00006ae28 [5/5]0xc00001a060
in main, l [99 2 3 4 5]
*************************
in main, mapInt 0xc00006adf0 0xc000062180
in mapTest, mapInt 0xc00006adf8 0xc000062180
in main, mapInt 0xc00006adf0 0xc000062180
in main, mapInt map[1:2 99:100]

分析

先看第一組結果,簡單int變量t,重新賦值爲2後,在內存中的地址不變。與Python不同,Python簡單對象賦值是引用重定向,引用一個新的對象,會改變id(obj)的結果。Goland是在原對象的基礎上修改,改變原對象中的內容。函數的傳參、返回值都會拷貝一個新對象,修改拷貝的對象不影響原對象。

再看第二組結果,切片類型l,打印第一個數值是變量地址,後面接的是[len/cap]數組內存地址,切片獨享保留着對數組內存地址的引用。第二次對切片賦值,同樣的對象地址不變,其len、cap、數組地址發生變化。在函數listTest中,形參同樣會生成一個新的對象,切片拷貝對象的len、cap、數組內存地址與元對象一致,如果改變拷貝切片中的元素,由於其引用同一個連續數組內存,原對象上也會得到體現,最後main中l[0]=99

再看第三組結果,map類型,打印的第一個值是map變量的地址,第二個參數是map對象引用的數據塊地址。同樣的,map對象作爲形參,會拷貝出一個新對象,與list類似,新老對象引用的數據塊地址一致,修改拷貝對象數據塊中的數據,會影響老對象的數據。

總結

  • Goland對存在的對象重新賦值,會改變原對象內存中的數據,與Python引用重定向相區別
  • Goland中slices、map、channel爲引用類型,其餘簡單類型爲值類型,值類型對象中空間中包含了對象所需的全部內容,引用類型除了基本信息外還引用着一塊可以共享的數據塊
  • Goland對象作爲函數參數、函數返回值、對象間賦值、copy等機制會從老對象拷貝出一個新的對象。這裏是淺拷貝機制,值類型完全複製,共用引用數據塊,複製引用地址。
  • 修改拷貝對象時,拷貝對象是引用類型,且修改的是引用數據塊中的數據,會影響所有引用該數據塊引用對象,這裏容易出bug。
  • 深拷貝可考慮序列化、反序列化來實現,深拷貝都比較耗時,非必須不建議使用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章