go语言 各数据类型传值函数改变是否影响原值

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u011088792/article/details/78121799

变量

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

结果:传值不改变,传指针改变
- 结构体和变量体现的是一样的

展开阅读全文

没有更多推荐了,返回首页