指针是一种存储变量内存地址(Memory Address)的变量。在学习指针之前,建议先记住下面3句话。
1. 类型前放 * 表示指针类型,这个类型的指针,指向这个类型的指针
2. 在变量前加 & 取地址符号,表示取该变量的地址
3. 在(指针)变量前加 * 表示反解,把地址解析成具体的值
指针变量的类型为 *T,该指针指向一个 T 类型的变量。
func main() {
var a int = 10 // 定义一个int类型的变量
var p *int // 定义一个整数类型的指针
p = &a //把a的地址给p
fmt.Println("a的地址为:",p) // a的地址为: 0xc00000a098
}
指针是引用类型,在go中,所有引用类型的零值都为 nil
指针的解引用可以获取指针所指向的变量的值。将 a 解引用的语法是 *a。
func main() {
var a int = 10 // 定义一个int类型的变量
var p *int // 定义一个整数类型的指针
if p == nil {
fmt.Println("指针的零值为nil") // 指针的零值为nil
}
p = &a //把a的地址给p
fmt.Println("p的解引用值为:", *p) // p的解引用值为: 10
}
指针也是一个变量,因此也存在对应的内存地址,所以就会存在 指针的指针
func main() {
var a int = 10 // 定义一个int类型的变量
var p *int // 定义一个整数类型的指针
var m **int
p = &a //把a的地址给p
m = &p //把p的地址给m
fmt.Println("p的解引用值为:", *p) // p的解引用值为: 10
fmt.Println("m的解引用值为:", *m) // m的解引用值为: 0xc0000aa058 -> p的值
fmt.Println("a的值为:", **m) // a的值为: 10
}
并且能够一直嵌套下去,也能够反解出值
可以向函数传递指针类型参数,并且可以通过指针修改值,影响外部变量的值
func main() {
a := 10
p := &a
test(p)
fmt.Println(a) // 99
}
func test(p *int) {
fmt.Println(p) // 0xc00000a098
fmt.Println(*p) // 10
*p = 99 // 修改值,不是改p,改p指向的值也就是a的值
}
需要注意的是,不要向函数传递数组的指针,而应该使用切片,使用切片的好处是,如果数组长度变了,函数不需要重写,而如果使用数组的指针,则需要重写函数。
func main() {
var a = [3]int{7,8,9}
var p *[3]int = &a
test2(p)
test3(a[:])
}
func test3(a []int) {
fmt.Println(a) // [7 8 9]
}
func test2(a *[3]int) {
fmt.Println(*a) // [7 8 9]
}
如果数组长度变成4,代码如下
func main() {
var a = [4]int{7,8,9}
var p *[4]int = &a
test2(p)
test3(a[:])
}
func test3(a []int) { // 去切片不需要修改
fmt.Println(a)
}
func test2(a *[4]int) { // 函数必须修改,才能使用
fmt.Println(*a)
}
如果是数组的指针,不需要解引用,直接使用即可,按索引取值即可
func main() {
var a = [4]int{7,8,9}
test2(p)
}
func test2(a *[4]int) {
fmt.Println(a[0]) // 7
fmt.Println(a[1]) // 8
}
指针数组指数组里面放了一堆指针,数组指针指指向数组的指针
func main() {
var a = [4]int{7,8,9}
// 数组指针
p := &a
}
// 指针数组
func test4(p *[4]int) {
fmt.Println((*p)[1]) // 先对a解引用--->数组--->再取值-->8
// (*p)[0]=10 先解引用,再修改 两种写法都可以
p[0]=10 // 把数组第0个位置的值改成了 10
fmt.Println(*p)
}