golang 完全是按值传递,所以正常的赋值都是值拷贝,当然如果类型里面嵌套的有指针,也是指针值的拷贝,此时就会出现两个类型变量的内部有一部分是共享的。
代码示例1:
package main
import (
"fmt"
)
type test struct {
a int
b []int
c map[string]int
}
func main() {
//需要给成员c分配内存,不如会抛出异常: panic: assignment to entry in nil map
//Slice 和 Map 的 nil 值,初始值为 nil 的 Slice 是可以进行“添加”操作的,但是对于 Map 的“添加”操作会导致运行时恐慌。( ﹁ ﹁ ) 恐慌。
t := &test{c:make(map[string]int, 1)}
t.a = 1
t.b = append(t.b, 2)
t.c["good"] = 3
t.c["hello"] = 4
t.c["nice"] = 5
f := *t
fmt.Println("before change")
fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)
fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)
fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)
f.a = 6
f.b = append(f.b, 7)
f.c["good"] = 8
f.c["hello"] = 9
f.c["nice"] = 10
fmt.Println()
fmt.Println("after change")
fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)
fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)
fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)
}
运行结果:
before change
t.a 1, f.a 1
t.b [2], f.b [2]
t.c map[good:3 hello:4 nice:5], f.c map[good:3 hello:4 nice:5]
after change
t.a 1, f.a 6
t.b [2], f.b [2 7]
t.c map[good:8 hello:9 nice:10], f.c map[good:8 hello:9 nice:10]
你会发现,将变量t赋值给变量f时候,f中的成员a和成员b 都获得了的拷贝,后续对f中成员a和b的改变,并不会影响t中成员a和b的改变,但是f中成员c获得拷贝是地址的拷贝,后续对f中成员c的改变,会影响t中成员c的改变,如何完整地获得变量t的拷贝,并且操作拷贝的那份数据并不会影响原始数据,查看下面示例2
代码示例2:
package main
import (
"fmt"
)
type test struct {
a int
b []int
c map[string]int
}
func deepCopy(dst, src *test) {
dst.a = src.a
dst.c = make(map[string]int, 1)
for key, val := range src.c {
dst.c[key] = val
}
}
func main() {
//需要给成员c分配内存,不如会抛出异常: panic: assignment to entry in nil map
//
t := &test{c:make(map[string]int, 1)}
t.a = 1
t.b = append(t.b, 2)
t.c["good"] = 3
t.c["hello"] = 4
t.c["nice"] = 5
f :=*t
deepCopy(&f, t)
fmt.Println("before change")
fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)
fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)
fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)
f.a = 6
f.b = append(f.b, 7)
f.c["good"] = 8
f.c["hello"] = 9
f.c["nice"] = 10
fmt.Println()
fmt.Println("after change")
fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)
fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)
fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)
}
运行结果:
before change
t.a 1, f.a 1
t.b [2], f.b [2]
t.c map[nice:5 good:3 hello:4], f.c map[hello:4 nice:5 good:3]
after change
t.a 1, f.a 6
t.b [2], f.b [2 7]
t.c map[good:3 hello:4 nice:5], f.c map[hello:9 nice:10 good:8]
除非特别指定,否则无法使用 nil 对变量赋值
nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特别指定的话,Go 语言不能识别类型,所以会报错。
错误信息:
package main
func main() {
var x = nil//error
_ = x
}
错误信息:
useof untyped nil
修正代码:
package main
func main() {
var x interface{} = nil
_ = x
}
Map 定长
创建 Map 的时候可以指定 Map 的长度,但是在运行时是无法使用 cap() 功能重新指定 Map 的大小,Map 是定长的。可以使用len
字符串无法为 nil
在 C 语言中是可以char *String=NULL,但是 Go 语言中就无法赋值为 nil。
参数中的数组
对于 C 和 C++ 开发者来说,数组就是指针。给函数传递数组就是传递内存地址,对数组的修改就是对原地址数据的修改。但是 Go 语言中,传递的数组不是内存地址,而是原数组的拷贝,所以是无法通过传递数组的方法去修改原地址的数据的。如果需要修改原数组的数据,需要使用数组指针(array pointer)。或者使用slice
网友评论