Golang 指针
我们知道变量是用来存储数据的,变量的本质是给存储数据的内存地址起了一个好记的别名。比如我们定义了一个变量a:=10,这个时候可以直接通过a这个变量来读取内存中保存的10这个值。在计算机底层a这个变量其实对应了一个内存地址。
指针也是一个变量,但它是一种特殊的变量,它存储的数据不是一个普通的值,而是另一个变量的内存地址。
要搞明白Go语言中的指针需要先知道三个概念
- 指针地址
- 指针类型
- 指针取值
Go语言中的指针操作非常简单,我们只需要记住两个符号:&:取地址,*:根据地址取值
指针地址和指针类型
每个变量在运行时都拥有一个地址,这个地址代表变量再内存中的位置。Go语言中使用 &字符放在变量前对变量进行取地址操作。Go语言中的值类型(int float bool string array struct)都有对应的指针类型如:
*int、,*int64、*string等
取变量指针的语法如下:
ptr := &v
举例:
指针取值
在对普通变量进行&操作符取地址后,会获得这个变量指针,然后可以对指针进行 *操作,也就是指针取值
package main
import "fmt"
func main() {
a := 100
a1 := &a
fmt.Println(a,*a1)
//改变变量的值,指针的值会跟着改变
a = 200
fmt.Println(a,*a1)
//改变指针的值,实际上就时改变量的值
b:=300
b1 := &b
fmt.Println(b,*b1)
*b1 = 100
fmt.Println(b,*b1)
}
一般来说,指针通常在函数传递参数,或者给某个类型定义新的方法时使用。Go 语言中,参数是按值传递的,如果不使用指针,函数内部将会拷贝一份参数的副本,对参数的修改并不会影响到外部变量的值。如果参数使用指针,对参数的传递将会影响到外部变量。
func add(num int) {
num += 1
}
func realAdd(num *int) {
*num += 1
}
func main() {
num := 100
add(num)
fmt.Println(num) // 100,num 没有变化
realAdd(&num)
fmt.Println(num) // 101,指针传递,num 被修改
}
new和make函数
需要注意的是,指针必须在创建内存后才可以使用,这个和 slice 和 map是一样的
// 引用数据类型map、slice等,必须使用make分配空间,才能够使用
var userInfo = make(map[string]string)
userInfo["userName"] = "zhangsan"
fmt.Println(userInfo)
var array = make([]int, 4, 4)
array[0] = 1
fmt.Println(array)
对于指针的错误示范:
// 指针变量初始化
var a *int
*a = 100
fmt.Println(a)
错误原因:在 Golang 中,对于引用类型的变量,我们在使用的时候不仅要声明它,还得为它分配内存空间,否则我们的值就没有办法存储。而对于值类型的声明不需要分配空间,是因为它们在声明的时候已经默认分配好了内存空间。
Golang中分配内存的函数主要是 new 和 make
make之前已经演示过,new是一个内置的函数,它的函数签名如下:
func new(Type) *Type
实际开发中new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。举个例子:
i := new(int)
fmt.Printf("%T \n",i) //*int
fmt.Println(i,*i) //0xc00000a0d8 0
*i = 123
fmt.Println(i,*i) //0xc00000a0d8 123
make和new的区别
- 两者都是用来做内存分配的
- make只能用于 slice map 以及 channel的初始化,返回的还是着三个引用类型的本身
- new用于类型的内存分配,并且内存默认值是类型的默认值,返回的是指向类型的指针