前言
- 其实从变量本身来说,go只有值传递,函数内的修改不会影响函数外。
- 但有一种特例是指针,go可以传指针给函数,指针指向申请出来的实际内存,也就是保存元素的内存,
这样在函数内的修改,可以影响到函数外。
分类看一下Go的函数传递:
- 基本数据类型int
- 类的实例
- 数组
基本类型(int)
值传递:
/* 引入单测包 */
import ("testing")
func TestSwap(t *testing.T) {
x := 100
y := 200
swap(x, y)
println("x:", x)
println("y:", y)
}
/* 定义相互交换值的函数 */
func swap(x, y int) int {
var temp int
temp = x /* 保存 x 的值 */
x = y /* 将 y 值赋给 x */
y = temp /* 将 temp 值赋给 y*/
return temp;
}
结果:
个人理解:传给swap函数的相当于一个值,swap函数会把形参作为一个局部变量新建,局部变量的修改,不影响原值。
传递指针
func TestSwap(t *testing.T) {
x := 100
y := 200
swapByPoint(&x, &y)
println("x:", x)
println("y:", y)
}
func swapByPoint(x, y *int) int {
var temp int
temp = *x /* 保存 x 的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y*/
return temp;
}
结果:函数里面的修改,影响了原值
个人总结:当传递指针给函数时,类似于传递了内存地址给函数,函数会对这块内存做修改,所以会影响原值。
类的实例
值传递
import (
"testing"
)
type Person struct{
Name string
}
func TestChangeName(t *testing.T) {
person := new(Person)
person.Name = "aaaaaaa"
changeName(*person)
println("name:", person.Name)
}
func changeName(person Person) {
person.Name = "bbbbbb"
}
结果:未改变原值
传递指针
func TestChangeName(t *testing.T) {
person := new(Person)
person.Name = "aaaaaaa"
changeName(person)
println("name:", person.Name)
}
func changeName(person *Person) {
person.Name = "bbbbbb"
}
结果:影响了原值
小结:传变量只会被当做局部变量,传指针才会影响原值
Slice(切片)
先上结论:
func test1(slice_2 []int) {
slice_2[1] = 6666 //函数外的slice确实有被修改
slice_2 = append(slice_2, 8888) //函数外的不变
}
func test2(slice_2 *[]int) { //这样才能用APPEND修改函数外的slice
*slice_2 = append(*slice_2, 6666)
}
原因
- slice(切片)是一个结构体,这个结构体中有一个指针,指向申请出来的实际内存。
- 传递slice的时候,这个结构体是值传递的,传递完成后,内存中有两个“slice结构体”,它们引用同一块“slice数组”,第一个例子slice_2[1]是修改这个数组内容,所以里面改了外面能看到改动.
- append这个函数则根据情况不同有两种工作方式,若你slice的cap足够,则直接修改其引用的数组区域并简单将len增加,并返回这个slice本身,即这时候h=append(h,…)之后,h还是引用原来的数组区域,只不过h的len增加了;若cap不够,则重新申请一块数组区域并将原来的数组内容拷贝过去后再进行追加元素操作,这时候append的返回的slice引用的是另一块内存了
来源链接:https://www.zhihu.com/question/47390706/answer/614694546
附上slice的结构:
// Slice结构体
struct Slice
{ // must not move anything
byte* array; // actual data
uintgo len; // number of elements
uintgo cap; // allocated number of elements
};
打印一下len和cap(容量),和原因中的解释是一样的:
总结:
- Go只有值传递,但可以传递指针
参考文档:
https://www.zhihu.com/question/47390706