书接上回,上回书中写道,数组已经和java中数组的区别。在go中数组的是数值类型,故需要指针指向数组的地址,从而进行修改。这次诉说,指针
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。(难度直接向下)
要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。
在内存中,一个数据需要存储,但是不能光存储,不去处理。要处理就必须在众多的数据中锁定我们所需的数据,这个就像,是在茫茫人海中一眼就看到你(只在灯火阑珊处)。所以此时就需要一个能够找到你的位置,也就是--------地址(在内存中,地址通常以32位,16进制表示)
我在程序中把赋值给变量A,把内存地址赋值给变量B。这时候变量B就是一个指针变量。
Go语言中的指针不能进行偏移和运算,因此Go语言中的指针操作非常简单,我们只需要记住两个符号:&(取地址)(获取引用)和 *(根据地址取值)(解引用)。
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。
Go语言中使用 & 字符放在变量前面对变量进行“取地址”操作。
Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。
func main() {
a := 10
b := &a
fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
fmt.Println(&b) // 0xc00000e018
}
a :代表被取地址的变量,类型为 int
b:用于接收地址的变量,ptr的类型就为 *int,称做 int 的指针类型。*代表指针。
变量、指针地址、指针变量、取地址、取值的相互关系和特性:
func main() {
//指针取值
a := 10
b := &a // 取变量a的地址,将指针保存到b中
fmt.Printf("type of b:%T\n", b)
c := *b // 指针取值(根据指针去内存取值)
fmt.Printf("type of c:%T\n", c)
fmt.Printf("value of c:%v\n", c)
}
取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
import "fmt"
func modifyArray(x int) {
x = 100
}
func modifyArray2(x *int) {
*x = 100
}
func main() {
//指针取值
a := 10
modifyArray(a)
fmt.Println(a)//10
modifyArray2(&a)
fmt.Println(a)//100
}
为什么会有这两个?其实我说实话我也挺懵逼的,看来到哪里都逃不过被new的命运。
在Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。
如错误例子:
func main() {
var a *int
*a = 100
fmt.Println(*a)
}
在这里我只做了声明但是没有给他分配内存空间,所以在底层迟迟找不到,然后就报超时。
对于值类型的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。
所以为了让我们声明的引用类型有内存空间,所以此时我们就需要,引入两个关键字对这种变量分配内存空间。
Go语言中new和make是内建的两个函数,主要用来分配内存。(如果是C语言就需要有释放内存的步骤,但是Go有自动回收的机制)
new是一个内置的函数:它的函数签名如下:
func new(Type) *Type
如何正确使用?
func main() {
// 声明指针类型
var a *int
// 为指针类型分配内空间
a = new(int)
// 进行赋值
*a = 10
fmt.Println(*a)
}
var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。
总结一下:
make也是用于内存分配,区别于new,它只是slice,map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型本身就是引用类型。所以没有必要去返回一个指针类型了。
make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。(这三个函数在后续会有讲解)
make的函数签名:
func make(t Type, size ...IntegerType) Type
func main() {
var b map[string]int
b = make(map[string]int, 10)
b["你好"] = 100
fmt.Println(b)
}
用的还是之前的三板斧
new与make的区别