golang指针概述
什么是指针
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针
指针是一种数据类型,用指针类型定义的变量通常只用于存储其它变量的地址
Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&
(取地址)和*
(根据地址取值)。
指针的声明
声明格式
var name *type
其中,name是指针的变量名,type是数据类型,前方的*代表这是一个指针类型,合起来*type
代表这是一个type类型的指针变量
指针的基本使用
- 由于指针变量存储的是变量的地址,使用&获取变量的地址,例如
var a int
,a的变量地址就是&a
- 使用*获取指针变量存储的地址指向的值,例如
var ptr *int = &a
,*ptr
就是变量a的值
代码如下:
package main
import "fmt"
func main() {
var a int = 10
var ptr *int = &a
fmt.Printf("a的值:%d,a的地址:%p\n", a, &a)
fmt.Printf("ptr的值:%p,ptr的地址:%p,ptr指向的值:%d\n", ptr, &ptr, *ptr)
*ptr = 20
fmt.Println("a的值为->", a)
}
运行结果:
a的值:10,a的地址:0xc00000e0a8
ptr的值:0xc00000e0a8,ptr的地址:0xc00000a028,ptr指向的值:10
a的值为-> 20
内存图:
如果改变*ptr的值,那么a的值同样发生改变,因为都是同一个地址指向的内存的值
指针通常作为函数的参数来使用,将基本数据类型的值传递改为引用传递
多重指针
由于指针变量存储的变量是地址,同时指针变量在内存中也有自己的地址,那么我们就可以用指针变量去存储另一个指针变量的地址,这就是多重指针
var a int = 10
var ptr1 *int = &a
var ptr2 **int = &ptr1
ptr2 -> ptr1 -> a
package main
import "fmt"
func main() {
var a int = 10
var ptr1 *int = &a
println("a的值:", a)
println("a的地址:", &a)
println("ptr1的值:", ptr1)
println("ptr1的地址存储的值:", *ptr1)
println("ptr1的地址:", &ptr1)
*ptr1 = 20
fmt.Println("---------------------------")
var ptr2 **int = &ptr1
println("ptr1的值:", ptr1)
println("ptr1的地址存储的值:", *ptr1)
println("ptr1的地址:", &ptr1)
println("ptr2的值:", ptr2)
println("ptr2的地址存储的值:", *ptr2)
println(**ptr2)
**ptr2 = 30
println(a)
println(*ptr1)
println(**ptr2)
}
数组指针
数组指针存储的是一个数组的地址
package main
import "fmt"
func main() {
arr := [4]int{1, 2, 3, 4}
fmt.Printf("arr->地址:%p\n", arr)
var ptrarr *[4]int = &arr
fmt.Printf("%p\n", ptrarr)
fmt.Printf("%p\n", &ptrarr)
fmt.Printf("%d\n", *ptrarr)
(*ptrarr)[0] = 100
fmt.Println(arr)
// 简化写法
ptrarr[1] = 200
fmt.Println(arr)
}
使用数组指针取数组里的值时,可以将*省去,(*ptrarr)[0]等同于ptrarr[0]
指针数组
指针数组本质上是一个数组,数组里的数据是一个个变量的地址
package main
import "fmt"
func main() {
// 指针数组
a := 1
b := 2
c := 3
d := 4
ptr := [4]*int{&a, &b, &c, &d}
fmt.Printf("%T\n", ptr)
fmt.Println(ptr)
//fmt.Println(*ptr)
*ptr[0] = 100
fmt.Println(a)
b = 200
fmt.Println(*ptr[1])
}
指针函数
在函数中指针可以作为参数或者返回值,作为参数时可以用于改变基本数据类型的值
package main
import "fmt"
func main() {
arr1 := f1()
fmt.Printf("arr1的类型:%T\n", arr1)
fmt.Println("arr1的地址", &arr1)
fmt.Println("arr1的值", arr1[0])
fmt.Println("arr1地址的值:", (*arr1)[0])
a := 1
fmt.Println(a)
f2(&a)
fmt.Println(a)
}
func f1() *[4]int {
arr := [4]int{1, 2, 3, 4}
return &arr
}
func f2(prt *int) {
fmt.Println("f2存储的地址:", prt)
fmt.Println("f2存储的地址的值:", *prt)
*prt = 100
}
new
new是一个函数
func new(Type) *Type
其中
1.Type表示类型,new函数只接受一个参数,这个参数是一个类型,通常是一个结构体
2.*Type表示类型指针,new函数返回一个指向该类型内存地址的指针,也就是返回的参数是一个指针类型。
使用new函数得到的是指针,并且该指针对应的值为该类型的默认值
func main() {
a := new(int)
b := new(bool)
fmt.Printf("%T\n", a) // *int
fmt.Printf("%T\n", b) // *bool
fmt.Println(*a) // 0
fmt.Println(*b) // false
}
new函数通常搭配结构体使用
package main
import "fmt"
type User struct {
name string
age int
}
func main() {
user := new(User)
fmt.Printf("user的类型:%T\n", user)
fmt.Println("user的值:", *user)
user1 := &User{}
fmt.Printf("user1的类型:%T\n", user1)
fmt.Println("user1的值:", *user1)
}
结果:
user的类型:*main.User
user的值: { 0}
user1的类型:*main.User
user1的值: { 0}
new(User)等价于&User{}