go語言 各數據類型傳值函數改變是否影響原值

變量

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}
*/

結果:傳值不改變,傳指針改變
- 結構體和變量體現的是一樣的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章