介绍
我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。所谓指针其实可以把它想像成一个箭头,这个箭头指向(存储)一个变量的地址。
因为这个箭头本身也需要变量来存储,所以也叫做指针变量。
Go 语言的取地址符是 &
,放到一个变量前使用就会返回相应变量的内存地址。
下面的例子演示了变量在内存中地址:
func main() {
var a int = 10
fmt.Printf("变量的地址: %x\n", &a )
}
指针声明格式如下:
var var_name *var-type
var-type 为指针类型,var_name 为指针变量名,*
号用于指定变量是作为一个指针。以下是有效的指针声明:
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮点型 */
小结:
-
&
取一个变量的地址 -
*
取一个指针变量所指向的地址的值
使用指针
指针使用流程:
- 定义指针变量。
- 为指针变量赋值。
- 访问指针变量中指向地址的值。
下面给出一个例子:
func main() {
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量的存储地址 */
fmt.Printf("a 变量的地址是: %x\n", &a )
/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\n", ip )
/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\n", *ip )
}
指针的一大用途就是可以将变量的指针作为实参传递给函数,从而在函数内部能够直接修改实参所指向的变量值。
看下面的例子:
func change(x *int) {
*x = 200
}
func main() {
var x int = 100
fmt.Println(x)
change(&x)
fmt.Println(x)
}
上面的例子中,change
函数的虚参为整型指针变量,所以在 main 中调用的时候传递的是x
的地址。然后在change
里面使用*x=200
修改了这个 x 的地址的值。
new
new这个函数挺神奇,因为它的用处太多了。这里还可以通过new来初始化一个指针。上面说过指针指向(存储)的是一个变量的地址,但是指针本身也需要地址存储。先看个例子:
func set_value(x_ptr *int) {
*x_ptr = 100
}
func main() {
x_ptr := new(int)
set_value(x_ptr)
//x_ptr指向的地址
fmt.Println(x_ptr)
//x_ptr本身的地址
fmt.Println(&x_ptr)
//x_ptr指向的地址值
fmt.Println(*x_ptr)
}
上面我们定义了一个x_ptr
变量,然后用new申请了一个存储整型数据的内存地址,然后将这个地址赋值给x_ptr
指针变量,也就是说x_ptr
指向(存储)的是一个可以存储整型数据的地址,然后用 set_value 函数将这个地址中存储的值赋值为100。所以第一个输出是x_ptr
指向的地址,第二个则是x_ptr
本身的地址,而*x_ptr
则是x_ptr
指向的地址中存储的整型数据的值。
Go 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil
。
nil
指针也称为空指针。nil
在概念上和其它语言的 null、None、nil、NULL一样,都指代零值或空值。
一个指针变量通常缩写为 ptr
。
实例:
func main() {
var ptr *int
// 空指针判断
if(ptr == nil) { /* ptr 不是空指针 */
fmt.Printf("ptr 的值为 : %x\n", ptr )
}
}