网站空间的价格,博客网站程序,大学生网站开发目的,android下载安装官方免费下载先说下结论 Go语言中所有的传参都是值传递#xff08;传值#xff09;#xff0c;都是一个副本#xff0c;一个拷贝。 值语义类型#xff1a;参数传递的时候#xff0c;就是值拷贝#xff0c;这样就在函数中就无法修改原内容数据。 基本类型#xff1a;byte、int、bool…先说下结论 Go语言中所有的传参都是值传递传值都是一个副本一个拷贝。 值语义类型参数传递的时候就是值拷贝这样就在函数中就无法修改原内容数据。 基本类型byte、int、bool、float32、float64、string等复合类型array、struct和指针等 引用语义类型参数传递的时候也是值拷贝不过是这样就可以修改原内容数据。 map、slice、chan和接口
引用类型值传递图解
下图以 slice 为例说明引用类型的变量作为实参传递给函数形参时是值传递拷贝 在Go语言里虽然只有传值但是我们也可以修改原内容数据因为参数是引用类型在函数传递引用类型的变量时会如上图进行值拷贝拷贝的数据里有引用变量引用的数据的地址。
值语义类型的参数传递
package mainimport fmtfunc main() {var by byte 123var i int64 10var boolean bool falsevar f32 float32 3.14var f64 float64 3.1415926var str string hello worldfmt.Printf(mian 函数中的变量 by 的内存地址是 %p\n, by)fmt.Printf(mian 函数中的变量 i 的内存地址是 %p\n, i)fmt.Printf(mian 函数中的变量 boolean 的内存地址是 %p\n, boolean)fmt.Printf(mian 函数中的变量 f32 的内存地址是 %p\n, f32)fmt.Printf(mian 函数中的变量 f64 的内存地址是 %p\n, f64)fmt.Printf(mian 函数中的变量 str 的内存地址是 %p\n, str)fmt.Println(函数调用前)callByValue(by, i, boolean, f32, f64, str)fmt.Println(函数调用后)fmt.Printf(被调函数中修改形参的值main 函数中打印结果为不变: %v\n, by)fmt.Printf(被调函数中打印结果为%v\n, i)fmt.Printf(被调函数中打印结果为%v\n, boolean)fmt.Printf(被调函数中打印结果为%v\n, f32)fmt.Printf(被调函数中打印结果为%v\n, f64)fmt.Printf(被调函数中打印结果为%v\n, str)
}func callByValue(by byte, i int64, boolean bool, f32 float32, f64 float64, str string) {fmt.Printf(被调函数中形参的 by 内存地址是%p\n, by)fmt.Printf(被调函数中形参的 i 内存地址是%p\n, i)fmt.Printf(被调函数中形参的 boolean 内存地址是%p\n, boolean)fmt.Printf(被调函数中形参的 f32 内存地址是%p\n, f32)fmt.Printf(被调函数中形参的 f64 内存地址是%p\n, f64)fmt.Printf(被调函数中形参的 str 内存地址是%p\n, str)by 10i 20boolean truef32 13.14f64 13.146666str hello golang
}mian 函数中的变量 by 的内存地址是 0xc00010200a , 值为 123
mian 函数中的变量 i 的内存地址是 0xc000102020 , 值为 10
mian 函数中的变量 boolean 的内存地址是 0xc000102028 , 值为 false
mian 函数中的变量 f32 的内存地址是 0xc00010202c , 值为 3.14
mian 函数中的变量 f64 的内存地址是 0xc000102030 , 值为 3.1415926
mian 函数中的变量 str 的内存地址是 0xc000104140 , 值为 hello world
函数调用前
被调函数中形参的 by 内存地址是0xc000102048 ,值为123
被调函数中形参的 i 内存地址是0xc000102050 ,值为10
被调函数中形参的 boolean 内存地址是0xc000102058 ,值为false
被调函数中形参的 f32 内存地址是0xc00010205c ,值为3.14
被调函数中形参的 f64 内存地址是0xc000102060 ,值为3.1415926
被调函数中形参的 str 内存地址是0xc000104160 ,值为hello world
函数内部修改值
函数调用后
被调函数中修改形参的值main 函数中打印结果为不变: 123
被调函数中打印结果为10
被调函数中打印结果为false
被调函数中打印结果为3.14
被调函数中打印结果为3.1415926
被调函数中打印结果为hello world从日志中可以发现main 函数实参的地址和被调函数callByValue中形参的地址不同在被调函数中修改形参的值并不会 影响实参变量的值。
指针类型
形参和实际参数内存地址不一样证明是值传递。由于形参和实参是指针类型指向同一个变量函数内对指针指向变量的修改会修改原内容数据。
package mainimport fmtfunc main() {var i int64 1fmt.Printf(main 函数中 i 内存地址是 %p\n, i) //0xc000104020 ip : icallByPointer(ip)fmt.Printf(改动后的值是: %v\n, i)
}func callByPointer(ip *int64) { //这里定义的args就是形式参数fmt.Printf(callByPointer形参的内存地址是%p\n, ip) //0xc000108068fmt.Printf(callByPointer形参的值是%p\n, ip) //0xc000104020*ip 10 //解引用
}main 函数中 i 内存地址是 0xc000104020
callByPointer形参的内存地址是0xc000108068
callByPointer形参的值是0xc000104020
改动后的值是: 10引用语义类型变量的参数传递
package mainimport fmtfunc main() {//切片var s make([]int64, 5, 10)s[0] 1s[1] 2s[2] 3s[3] 4s[4] 5fmt.Printf(原始切片 len %v ,cap %v, len(s), cap(s))var p sfmt.Printf(原始切片 取地址(s)%p ; \n直接对原始切片取地址( p)%p \n, s, p)fmt.Printf(原始切片 底层数组的内存地址s %p \n原始切片 第一个元素的内存地址(s[0]) %p\n, s, s[0])callBySliceParam(s)fmt.Printf(改动后的值是: %v\n, s)
}func callBySliceParam(s1 []int64) {fmt.Printf(函数里,函数参数切片取地址 %p\n, s1)fmt.Printf(函数里,函数参数切片的底层数组的内存地址是 %p \n, s1)fmt.Printf(函数里,函数参数切片第一个元素的内存地址 %p \n, s1[0])s1[0] 10
}原始切片 len 5 ,cap 10原始切片 取地址(s)0xc0001120a8 ;
直接对原始切片取地址( p)0xc0001120a8
原始切片 底层数组的内存地址s 0xc00012c000
原始切片 第一个元素的内存地址(s[0]) 0xc00012c000
函数里,函数参数切片取地址 0xc0001120d8
函数里,函数参数切片的底层数组的内存地址是 0xc00012c000
函数里,函数参数切片第一个元素的内存地址 0xc00012c000
改动后的值是: [10 2 3 4 5]通过输出日志可以清楚地看到切片作为引用类型的特点传递切片时实际上是传递了切片的副本但这个副本仍然指向同一个底层数组。因此对切片的修改会影响到原始切片。