go系列之值传递引用传递与指针传递

Posted mazhimazhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go系列之值传递引用传递与指针传递相关的知识,希望对你有一定的参考价值。

 

1、关于值传递、引用传递与指针传递

 

当一个变量或者新值被创建时, 如果没有为其明确指定初始值,go语言会自动初始化其值为此类型对应的零值, 各类型零值如下:
 
false : bool,
0: integer
0.0: float
"": string
nil : pointer, function, interface, slice, channel, map

对于复合类型, go语言会自动递归地将每一个元素初始化为其类型对应的零值。比如:数组, 结构体。 

nil 是专门为go语言的指针类型和引用类型准备的,go语言的数组和结构体可是值类型, 切片、字典或通道为引用类型。所以如果数组作为函数参数时,因为是值类型, 所以要复制 。

在go语言中没有引用传递,只有值传递。

例1:值传递

func main() {
	a := []string{"a", "b"}
	test(a)
	fmt.Println(a)
}

func test(b []string) {
	b = []string{"cc", "cc"}
}  

打印出来后值为:[a b],表明在传递时是复制了一份单独的数组结构。

 

指针传递也是值传递。

例2:指针传递,也是值传递

func main() {
	a := &[]string{"a", "b"}
	test(a)
	fmt.Println(*a)
}

func test(b *[]string) {
	b = nil
}

打印出来后为:[a b]。传递指针时,能修改指针所指向的值,并不能修改指针本身的值。

 

传引用

var a Object
modify(a) // 修改a的值
print(a)

如果函数modify修改a的值, 然后print打印出来的也是修改后的值,那么就可以认为modify是通过引用的方式使用了参数a。而如上例子证明了指明传递是值传递。 

例3:引用传递

func main() {
    a := new(int)
    fmt.Println(a)
    func() {
        a = nil
    }()
    fmt.Println(a)
}

打印结果为:

0xc042008220
<nil>

 

关于指针传递与引用传递参考:https://studygolang.com/articles/4810

 

 

2、关于go中的map

go语言中的map不是协程安全的,如果要多个协程对同 一个map进行写操作,则会出错:

fatal error: concurrent map writes

举例:

func main() {
	Map := make(map[int]int)

	for i := 0; i < 100000; i++ {
		go writeMap(Map, i, i)
		go readMap(Map, i)
	}

}

func readMap(Map map[int]int, key int) int {
	return Map[key]
}

func writeMap(Map map[int]int, key int, value int) {
	Map[key] = value
}

因为map为引用类型,所以即使函数传值调用,参数副本依然指向映射m, 所以N个goroutine并发写同一个映射m,共享资源会遭到破坏。

解决办法就是加锁,或者channel排队串行化。

 

以上是关于go系列之值传递引用传递与指针传递的主要内容,如果未能解决你的问题,请参考以下文章

Go 指针与引用:值传递和址传递

Golang - 指针与引用

go的值类型和引用类型1——传递和拷贝

Golang中函数传参存在引用传递吗?

GO语言复合类型01---指针

Java小白进阶之值传递-地址传递