关于go 函数传值问题
- 什么类型变量属于默认引用传值,什么类型变量默认属于复制传值?
- 如何修改默认的传参方式?
1、int ,int32,int64 类型传参
1 | golang复制代码func toValueInt(val int){ |
执行结果
1 | js复制代码1 |
分析 main 函数创建一个变量并赋值 1,toValueInt(a) 函数修改为2,然后打印结果1,说明默认int 传参默认为 值传递。
下面我们实现int引用传值
1 | golang复制代码func toValueInt(val *int){ |
执行结果
1 | js复制代码2 |
分析 toValueInt 函数为指向int的一个指针,传参的时候通过&符取地址,然后在函数中修改这个值,结果变为2
其他整型类型类似,不做过多解释
2、string 类型传参
1 | gloang复制代码func toValueString(val string){ |
执行结果
1 | js复制代码1 |
和int类型一样,默认string 传参默认为 值传递
实现引用传值
1 | js复制代码func toValueString(val *string){ |
同理int类型传值
3、数组类型传参
1 | js复制代码func toValueList(val [3]int){ |
输出结果
1 | js复制代码[1 2 3] |
分析 数组类型默认是值传递
实现引用传值
1 | golang复制代码func toValueList(val *[3]int){ |
**输出结果 **
1 | js复制代码[4 5 5] |
分析 和上面的类型一致,通过传递指针来实现
4、slice 类型切片传值 ,这个类型比较特殊
首先看一种情况,通过下标赋值
1 | golang复制代码func toValueSplice(val []int){ |
输出结果
1 | js复制代码[2] |
分析下 ,定义数组[]int{1},调用函数 toValueSplice ,通过下标修改数组值,修改成功。
说明slice 在直接通过修改下标的时候是引用传值。
传递的切片长度是1,我们在数组里尝试给 索引1的位置赋值
1 | golang复制代码func toValueSplice(val []int){ |
执行结果
1 | js复制代码panic: runtime error: index out of range [1] with length 1 |
说明参数传递进去的数组长度是1,越位赋值。
接着我们通过append追加值
1 | golang复制代码func toValueSplice(val []int){ |
输出结果
函数中打印
1 | js复制代码[1 2] |
main 函数打印
1 | js复制代码[1] |
说明 main函数打印结果仍然是[1],toValueSplice函数中通过append 追加值的时候,打印出结果是[1 2] 说明slice在函数中通过append追加值这是值传递。
总结下
通过下标赋值是引用传值,但是不能改变原参数slice长度
通过append追加值,可以改变参数slice长度,但是不能修改原参数slice 值,属于值传递。
实现引用传值,且修改slice 长度
1 | golang复制代码func toValueSplice(val *[]int){ |
执行结果
函数中打印
1 | js复制代码[1 2] |
main 函数打印
1 | js复制代码[1 2] |
分析 通过传递地址来修改slice值
5、map传值
1 | golang复制代码func toValueMap(val map[string]int){ |
输出结果
1 | js复制代码map[1:2] |
说明,我们在函数里面修改了原值,map类型默认是引用传值
如何打破引用传值
方法一
1 | golang复制代码func toValueMap(val map[string]int){ |
执行结果
1 | js复制代码map[1:1] |
分析 在函数toValueMap里面 创建 val1 变量,然后通过for 循环 将 val 的值赋值给 val1,然后在将 val1 赋值给 val。有些小伙伴看到这里就很疑惑,为啥这么麻烦呢?直接 val1 = val ,然后修改 val1 的值,不就可以了吗?这里咱们尝试一下
1 | golang复制代码func toValueMap(val map[string]int){ |
输出结果
1 | js复制代码map[1:2] |
说明 原参数值被修改了,map 是引用传值,在函数里面通过等号赋值仍然是引用赋值,恐怖吗?如果在实际中这么用,就回出现混乱,莫名其妙变量值就被意外一个函数修改了。
还有一种打破引用传值的方式是通过,json 序列化来修改
1 | golang复制代码func toValueMap(val map[string]int){ |
代替了 for range
5、struct 类型传值
1 | golang复制代码type ss struct { |
执行结果
1 | js复制代码{1} |
说明 struct传值默认是值传递
实现引用传递
1 | golang复制代码type ss struct { |
执行结果
1 | js复制代码{2} |
6、chan 类型传值
1 | js复制代码var ch chan int |
输出结果
1 | js复制代码1 2 |
说明 main 函数里面创建了 ch,并且长度为2,然后写入1 ,接着调用 toValueChan(ch),函数里面写入2,通过 fmt.Println( <-ch,<-ch),连续读取两次,得到1,2 ,说明 toValueChan 里面对 ch 变量修改是生效了的 ,chan 类型是引用传值。
chan 打破引用传值,这个人建议觉得没有多大用,现实使用中更多是用引用传值。
总结
int ,int32,int64,string,list,struct 这几种类型是值传递
map,chan 是引用传值
splice 在通过下标赋值的时候是引用传值,通过append 追加值的时候是值传递
如果觉得文章对您有帮助,请下赞,您的认可是我更新的动力,谢谢大家
本文转载自: 掘金