记录一次go全局变量赋值的问题

go 语言给变量赋值

我们先看看go语言如何给一个变量赋值

1
2
3
4
5
6
# 第一种, 在声明的同时进行赋值的话,是可以不用指定变量的类型的,如果只是声明的话,是需要的
var num int = 0
var num = 0

# 第二种, 不用写var关键字,使用新的赋值符号“:=” ,如下,跟上面的声明式变量是一样的
num := 0

实际工作中遇到的问题

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

// cache -----
type Cache struct {
}

func (c Cache) set() {
fmt.Println("cache set", c)
}

// cache ----- end

// main ------

var cache *Cache

func init() {
cache := &Cache{}
fmt.Println("init", cache)
}

func main() {
cache.set()
}

打印结果如下,提示cache是无效的,经过debug发现,cache是nil,并没有实际赋值成功

1
2
3
4
5
6
7
8
init &{}
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10995a8]

goroutine 1 [running]:
main.main()
*****.go:25 +0x28
exit status 2

后来发现是使用了:=导致的,:=是声明并赋值,会在init方法中新声明一个变量,并给这个变量赋值。
所以我们是在init中的cache进行了赋值,并没有对全局的cache进行赋值。
:=改成=问题解决

疑问

在上面的异常代码中,cache是一个指针类型,下面的代码中我将cache声明为一个普通的变量,代码正常运行
为什么指针类型不可以,普通类型却是可以的,如果:=真是我上面所说的话,那普通类型应该也不可以正常运行才对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

// cache -----
type Cache struct {
}

func (c Cache) set() {
fmt.Println("cache set", c)
}

// cache ----- end

// main ------

var cache Cache

func init() {
cache := Cache{}
fmt.Println("init", cache)
}

func main() {
cache.set()
}

带着这个疑问,我们通过增加打印变量的地址信息来确定一下

1
2
3
4
5
6
7
8
9
10
func init() {
fmt.Printf("init %p\n", &cache)
cache := Cache{}
fmt.Printf("init %p\n", &cache)
}

func main() {
fmt.Printf("main %p\n", &cache)
cache.set()
}

执行结果

1
2
3
4
init 0x1195940
init 0x1195ab8
main 0x1195940
cache set {}

可以看到的是,cache还未进行初始化的时候地址跟main中的地址是一样的,并没有因为赋值而改变,我们在这里可以猜测是对于普通的变量,go语言已经帮我们进行了初始化的操作,所以普通变量是可以正常运行的