變量
func main() {
v := 12
fmt.Println("src:", v)
change(v)
fmt.Println("after change:", v)
p := 12
changep(&p)
fmt.Println("after changep:", p)
}
func change(v int) {
v = 33
}
func changep(p *int) {
*p = 55
}
/*
src: 12
after change: 12
after changep: 55
*/
可以看到:v的值依然是12,而p的值由12改變爲55
變量在傳遞函數時是值拷貝,會在內存中另開闢一個地方存放拷貝值,而形參就指向這個地址
當你傳遞指針給函數時,形參和原變量同時指向改地址,所以改變地址中存放的值,則原變量的值當然會變化
同理於任何實際的值,如數組元素,結構體元素
普通數組
func main() {
arr := [3]int{13, 23, 543}
fmt.Println("src:", arr)
change(arr)
fmt.Println("after change:", arr)
changep(&arr)
fmt.Println("after change p:", arr)
}
func change(a [3]int) {
a[2] = 34
}
func changep(p *[3]int) {
p[1] = 45
}
/*
src: [13 23 543]
after change: [13 23 543]
after change p: [13 45 543]
*/
結果:543依然是543,23變成了45
- go中普通數組和變量在底層是差不多的
slice
func main() {
arr := []int{13, 23, 543}
fmt.Println("src:", arr)
change(arr)
fmt.Println("after change:", arr)
}
func change(a []int) {
a[2] = 34
}
/*
src: [13 23 543]
after change: [13 23 34]
*/
依然是這個例子,但是543變成了34
- slice其實包含了三部分,指針、長度、容量
- 所以slice傳遞的其實本身就有指針特性,不存在&arr這種操作
func main() {
arr := make([]int, 3)
fmt.Printf("src:%v, p:%p, len:%d, cap:%d\n", arr, arr, len(arr), cap(arr))
add(arr)
fmt.Println(arr)
// 容量10
arr2 := make([]int, 3, 10)
fmt.Printf("src:%v, p:%p, len:%d , cap:%d\n", arr2, arr2, len(arr2), cap(arr2))
add(arr2)
fmt.Println(arr2)
fmt.Println(arr2[:4])
}
func add(a []int) {
a = append(a, 43)
fmt.Printf("add: %p\n", a)
}
/*
src:[0 0 0], p:0x115da140, len:3, cap:3
add: 0x115d8480
[0 0 0]
src:[0 0 0], p:0x115e02d0, len:3 , cap:10
add: 0x115e02d0
[0 0 0]
[0 0 0 43]
*/
結果: 使用append函數對原slice是沒有影響的,但是有差別
slice上面說了有個容量,他是可變的,當你不定義容量時,默認是初始化時的長度就是容量。而當你新增元素超過容量上限時,會在內存中重新分配地址,容量爲之前的2倍,用於存儲新slice,返回新的物理地址
首先我們要明白,所有不含&的都是傳遞拷貝值,slice是因爲本身含指針,導致修改元素值影響原slice,但是如果修改形參本身,而不是slice中的元素,是不會對原slice產生影響的,如arr1其實新slice傳遞給了形參a,但是隻是傳遞給了拷貝值,而並非原slice
其實新值43都插入成功了,只不過arr1插入到了新分配的slice,但是新slice並沒有返回回去,而arr2容量足夠,則不用重新分配,我們取arr2的前四位可以看到43已經成功插入,因爲arr2本身長度只有3位,所以他的值只取了前三位
map
func main() {
m := map[int]string{1: "one", 2: "two", 3: "three"}
fmt.Println(m)
change(m)
fmt.Println(m)
add(m)
fmt.Println(m)
}
func change(a map[int]string) {
a[1] = "four"
}
func add(a map[int]string) {
a[5] = "five"
}
/*
map[2:two 3:three 1:one]
map[1:four 2:two 3:three]
map[1:four 2:two 3:three 5:five]
*/
結果: 1的值由one改爲了four,新增了5:five
- map和slice差不多,修改值都會改變原值,都是可變長度,但是map沒有容量概念,新增值和使用delete函數也能改變原值,這裏就不都進行演示
struct
func main() {
p := Person{
Name: "dabai",
Age: 3,
}
change(p)
fmt.Println(p)
changep(&p)
fmt.Println(p)
}
func change(p Person) {
p.Age = 4
}
func changep(p *Person) {
p.Age = 5
}
/*
{dabai 3}
{dabai 5}
*/
結果:傳值不改變,傳指針改變
- 結構體和變量體現的是一樣的