go语言函数传值问题

go语言的函数都是拷贝

数组

func myFunction(i int, arr [2]int) {
    i = 29
    arr[1] = 88
    fmt.Printf("in my_funciton - i=(%d, %p) arr=(%v, %p)\n", i, &i, arr, &arr)
}

func main() {
    i := 30
    arr := [2]int{66, 77}
    fmt.Printf("before calling - i=(%d, %p) arr=(%v, %p)\n", i, &i, arr, &arr)
    myFunction(i, arr)
    fmt.Printf("after  calling - i=(%d, %p) arr=(%v, %p)\n", i, &i, arr, &arr)
}
$ go run main.go
before calling - i=(30, 0xc000072008) arr=([66 77], 0xc000072010)
in my_funciton - i=(29, 0xc000072028) arr=([66 88], 0xc000072040)
after  calling - i=(30, 0xc000072008) arr=([66 77], 0xc000072010)

结构体和指针

type MyStruct struct {
    i int
}

func myFunction(a MyStruct, b *MyStruct) {
    a.i = 31
    b.i = 41
    fmt.Printf("in my_function - a=(%d, %p) b=(%v, %p)\n", a, &a, b, &b)
}

func main() {
    a := MyStruct{i: 30}
    b := &MyStruct{i: 40}
    fmt.Printf("before calling - a=(%d, %p) b=(%v, %p)\n", a, &a, b, &b)
    myFunction(a, b)
    fmt.Printf("after calling  - a=(%d, %p) b=(%v, %p)\n", a, &a, b, &b)
}
$ go run main.go
before calling - a=({30}, 0xc000018178) b=(&{40}, 0xc00000c028)
in my_function - a=({31}, 0xc000018198) b=(&{41}, 0xc00000c038)
after calling  - a=({30}, 0xc000018178) b=(&{41}, 0xc00000c02

map

map结构

type hmap struct {
    count     int
    flags     uint8
    B         uint8
    noverflow uint16
    hash0     uint32
    //桶
    buckets    unsafe.Pointer
    oldbuckets unsafe.Pointer
    nevacuate  uintptr

    extra *mapextra
}

type mapextra struct {
    overflow    *[]*bmap
    oldoverflow *[]*bmap
    nextOverflow *bmap
}

结论:
函数中改变map的值会影响函数外的map变化,由于map的桶指向是一个地址函数传递的时候会拷贝当前的地址的值,当map扩容的时候桶的值会传给oldbuckets 取值,所以修改map的值会影响函数外的map的变化

func TestValue(t map[int]int) {
   fmt.Printf("%v  %p\n", t, &t)
   t[1] = 2
   fmt.Printf("%v  %p\n", t, &t)
}

func main() {
   t := make(map[int]int, 0)
   t[1] = 1
   fmt.Printf("%v  %p\n", t, &t)
   TestValue(t)
   fmt.Printf("%v  %p\n", t, &t)

}

输出

map[1:1]  0xc000006028
map[1:1]  0xc000006038
map[1:2]  0xc000006038
map[1:2]  0xc000006028

切片

结构

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

结论:
1.数组在不超过其初始化容量的时候,修改当前data所指地址的值所以例子1中修改切片的值会修改切片的内容。
2.例子2中当超过切片容量时,Data指针地址产生变化会形成一个新的数组,由于函数传递是值拷贝所以只会修改当前切片的值。
例子1

func main() {
   s := make([]int, 2)
   fmt.Printf("%v  %p\n", s, &s)
   mdSlice(s)
   fmt.Printf("%v  %p\n", s, &s)
}

func mdSlice(s []int) {
   fmt.Printf("%v  %p\n", s, &s)
   s[0] = 1
   s[1] = 2
   fmt.Printf("%v  %p\n", s, &s)
}

输出:

[0 0]  0xc000004078
[0 0]  0xc0000040a8
[1 2]  0xc0000040a8
[1 2]  0xc000004078

例子2

func main() {
   s := make([]int, 0)
   fmt.Printf("%v  %p\n", s, &s)
   mdSlice(s)
   fmt.Printf("%v  %p\n", s, &s)
}

func mdSlice(s []int) {
   fmt.Printf("%v  %p\n", s, &s)
   s = append(s, 1)
   s = append(s, 2)
   fmt.Printf("%v  %p\n", s, &s)
}

输出

[]  0xc000004078
[]  0xc0000040a8
[1 2]  0xc0000040a8
[]  0xc000004078
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容