一、指针
指针的定义
对于引用数据类型来说,变量指向的不是数据值本身,而是指向数据值本身所在的内存空间的地址,而指针就是用来存储内存地址且只能是内存地址的一个变量。
变量的本质就是给存储数据的内存地址起一个更通俗易懂的别名。
// 定义指针变量的方式
var 变量名 *变量数据类型
func main() {
var a = 1
// 定义一个指针变量,指针变量存储 int 数据类型
var zulu *int = &a
fmt.Printf("%T\n", zulu)
fmt.Printf("%v\n", zulu)
fmt.Printf("%v\n", *zulu)
}
执行上述代码,输出结果如下:
*int
0xc0000b2008
1
上述代码中 *int 就是指针的类型,指针变量指向内存地址中所存储的值可以通过 *指针变量名来获取,当然也可以不通过定义指针变量的方式而是直接通过 &变量名 获取内存地址或者通过 *&变量名 来获取内存地址所指向的值。
上面讲到过指针变量只能存储地址,也就是说定义指针变量的时候是不能直接赋值的,一定要给一个内存地址,而 &变量名 可以获取内存地址,上述代码就是将 a 变量的内存地址赋值赋值给指针 zulu,如果直接赋值会报错:
另外指针定义时,指针变量指向的类型(如*int)必须和存储地址中存储的数据类型必须一致(也必须存储 int),否则会报错:
指针有多种数据类型,指针指向的类型必须和内存地址对应的数据类型一致。指针指向的内存地址可以通过 & 获取,内存地址指向的值可以通过 *&a 获取。
make 函数和 new 函数
// filename: ex5.go
func main() {
var info map[string]string
info["name"] = "tony"
fmt.Println(info)
}
执行上述代码,输出结果如下:
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
/ex5.go:9 +0x32
这里执行报错是因为没有初始化,Go 语言中对于引用数据类型使用的时候不仅要声明它,还要分配内存空间,否则赋值的时候就无法存储。对于值类型的声明不需要分配内存空间,因为在声明的时候就已经默认分配好了内存地址。
Go 中分配内存需要使用到两个内置函数 make 函数和 new 函数,其中:
- make 函数用于创建切片 slice、字典 map 和 管道 channel 等该数据类型时分配内存空间
- 只能对内置数据类型进行申请内存空间
- 返回数据值本身
- new 函数的作用是为类型申请一片内存空间,并返回指向这块内存空间的内存地址(返回一个指针)
- new 方法主要是给 struct 一类非内置数据类型申请内存空间
- 返回一个指针
func main() {
var info = make(map[string]string)
info["name"] = "tony"
fmt.Println(info)
}
执行上述代码,输出结果如下:
map[name:tony]
使用 make 函数给字典 info 分配内存空间。
func main() {
// 分配内存,返回内存地址
sli := new([]int)
// *sli 表示切片的值
*sli = append(*sli, 1)
fmt.Printf("%T, %T\n", sli, *sli)
// 分配内存,返回内存地址
infoPoi := new(map[string]string)
// 内存地址指向的值赋值给info
info := *infoPoi
// 初始化 info
info = map[string]string{}
info["name"] = "zhangsan"
fmt.Printf("%v, %T, %v, %T\n", infoPoi, infoPoi, info, info)
user := make(map[string]string)
user["username"] = "tony"
fmt.Println(user)
fmt.Printf("%T\n", user)
}
执行上述代码,输出结果如下:
*[]int, []int
&map[], *map[string]string, map[name:zhangsan], map[string]string
map[username:tony]
map[string]string
new 函数返回的是内存地址,既指针类型,如果需要给内存地址指向的数据赋值,需要通过 *指针变量 来获取具体的数值后进行操作。
func main() {
// new 初始化自定义结构体
stuPoint := new(Student)
stu := *stuPoint
stu.stuName = "mark"
stu.stuAge = 12
fmt.Printf("%v, %v, %T, %T", stu, stuPoint, stu, stuPoint)
}
type Student struct {
stuName string
stuAge int
}
执行上述代码,输出结果如下:
{mark 12}, &{ 0}, main.Student, *main.Student
这里使用 new 初始化了一个自定义的结构体,关于结构体将在下面的内容中讲到,先混个眼熟。