指针:
区别于 C/C++ 中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。
Go中指针的3个概念:指针地址,指针类型,指针取值。
Go语言中的指针:
Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而不需要拷贝数据。类型指针不能进行偏移和运算。
Go中指针只有两个操作,& 取地址,* 根据地址取值
指针地址与指针类型:
每个变量在运行时都有一个内存地址。Go中使用 &变量 进行取地址操作。Go中的值类型都有对应的指针类型,比如:*int,*string 等。
func main() { a := 10 b := &a fmt.Printf("a:%d ptr:%p ", a, &a) // a:10 ptr:0xc00001a078 fmt.Printf("b:%p type:%T ", b, b) // b:0xc00001a078 type:*int fmt.Println(&b) // 0xc00000e018 }
指针取值:
对变量使用&操作获取地址后,会获得这个变量的指针,可以对指针使用*操作,对指针进行取值。
func main() { //指针取值 a := 10 b := &a // 取变量a的地址,将指针保存到b中 fmt.Printf("type of b:%T ", b) // type of b:*int c := *b // 指针取值(根据指针去内存取值) fmt.Printf("type of c:%T ", c) // type of c:int fmt.Printf("value of c:%v ", c) // value of c:10 }
取地址操作符& 和 取值操作符* 是一对互补操作符,&取出地址,*根据地址取出 地址指向的值
变量,指针地址,指针变量,取地址,取值 的相互关系和特性如下:
- 对变量进行取地址操作&,可以获得这个变量的 指针变量
- 指针变量的值,就是 指针地址
- 对 指针变量进行取值操作*,可以获得指针变量指向的原变量的值,
package main import "fmt" func modify1(x int) { x = 100 } func modify2(x *int) { *x = 200 } func main() { x := 10 modify1(x) fmt.Println(x) // 10 modify2(&x) fmt.Println(x) // 200 }
空指针:
当一个指针被定义后没有分配到任何变量时,它的值为 nil,即 空指针
package main import "fmt" func main() { var p *string fmt.Println(p) fmt.Printf("p的值是 %v ",p) if p != nil { fmt.Println("p不是空值") } else { fmt.Println("p是空值") } }
new 和 make:
package main import "fmt" func main() { var a *int *a = 100 fmt.Println(*a) var b map[string]int b["测试"] = 100 fmt.Println(b) }
执行上面的代码会引发panic
在Go中,对于引用类型的变量,我们在使用的时候,不仅要声明它,还要为它分配内存空间,否则就没有办法存储值。
对于值类型的声明不需要分配内存空间,因为在声明的时候,就已经默认分配好了内存空间。
要分配内存,需要使用make和new,他们是两个内建的函数,主要用来分配内存。
new:
package main import "fmt" func main() { a := new(int) b := new(bool) fmt.Printf("%T ",a) // *int fmt.Printf("%T ",b) // *bool fmt.Println(*a) // 0 fmt.Println(*b) // false }
package main import "fmt" func main() { var a *int a = new(int) *a = 10 fmt.Println(*a) }
var a *int,只是声明了一个指针变量a,但是没有初始化,指针作为引用类型需要初始化后才能拥有内存空间,才可以赋值。
make
make也是用于内存分配的,区别于new,它只用于slice,chan以及map的内存创建,而且它返回的类型就是三个类型的本身,而不是他们的指针类型,因为这三种类型就是引用类型,没必要返回他们的指针。
func make(t Type, size ...IntegerType) Type
make函数是无可替代的,我们在使用slice,map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。
package main import "fmt" func main() { var b map[string]int b = make(map[string]int,10) b["测试"] = 100 fmt.Println(b) // map[测试:100] }
new 与 make 的区别:
都是用来做内存分配的
make只用于 slice,map,channel的初始化,返回的是 这三个引用类型的本身
new用于类型的内存分配,并且内存对应的值为类型的默认零值,返回的是 指向类型的指针。