Golang - 指针
什么是指针
基本数据类型和数组,变量存储的是值,也就是值类型。
指针类型,变量存储的是另外一个变量的内存地址,也就是指针类型。
package main
import "fmt"
func main() {
var name string = "smile"
var ptr *string = &name
fmt.Printf("变量name的值是%v\nptr指针的值是%v",name,ptr)
}
程序的输出结果:
变量name的值是smile
ptr保存的值是0xc000088220
ptr本身的内存为0xc0000ce018
结合程序,画出内存示意图如下:

在上图中,变量name的值是smile,存储在地址为0xc00004c230的内存中。变量ptr存储了变量name的地址。现在可以说ptr指向name
指针的声明
一个指针变量指向一个值得内存地址
类似于变量和常量,在使用指针前你需要声明指针。指针的声明格式如下:
var var_name *var_type
var_type为指针类型,var_name为指针的变量名,*号用于指定变量是作为一个指针。
var ip *int //指向整形
var if *float //指向浮点型
让我们写一些代码
package main
import "fmt"
func main() {
var name string = "smile"
var pname *string
pname = &name
fmt.Printf("panme的类型是%T\n值是%v",pname,pname)
}
'&'操作符用来获取到一个变量的地址。在上面的程序中,我们讲name的地址赋予pname(pname的类型为*string)。现在我们说pname指向了name。程序的输出为:
panme的类型是*string
值是0xc000088220
指针的空值
指针的空值为nil
package main
import "fmt"
func main() {
name := "smile"
var pname *string
if pname == nil {
pname = &name
fmt.Println(pname)
}
}
在上面的程序中 pname的初始值为nil。接着将name的地址赋值给pname。程序的输出结果为:
pname的值为 <nil>
pname的值为 0xc00004c230
指针解引用
解引用指针的意思是通过指针访问指向的值。指针pname的解引用就是*pname
让我们通过一个程序看一下它是怎么工作的。
package main
import "fmt"
func main() {
name := "smile"
pname := &name
fmt.Printf("pname的值为%v\n指向的值为%v",pname,*pname)
}
我们将panme解引用并打印这个解引用得到的值。和我们预期的一样,程序打印的是name的值smile,程序的输出为:
pname的值为0xc00004c230
指向的值为smile
让我们写一个程序,该程序使用指针改变name的值
package main
import "fmt"
func main() {
name := "smile"
pname := &name
fmt.Printf("pname的值为%v\n指向的值为%v\n",pname,*pname)
*pname = "dylan"
fmt.Printf("pname的值为%v\n指向的值为%v\n",pname,*pname)
}
在上面的程序中,我们将pname指向的值进行了修改,因此name的值也被改变了。程序的输出结果为:
name的值为smile
name的值为dylan
传递指针给函数
package main
import "fmt"
func main() {
var name string = "smile"
fmt.Println("函数调用之前的值",name)
change(&name)
fmt.Println("函数调用之前的值",name)
}
func change(value *string) {
*value = "dylan"
}
我们name的地址符传递给函数change。在函数change内部,通过解引用修改了name的值。程序的输出结果如下:
函数调用之前的值 smile
函数调用之前的值 dylan
不要传递指向数组的指针给函数,而是使用切片
假设我们需要通过函数修改一个数组。一个办法是将数组的指针作为参数传递给函数
package main
import "fmt"
func main() {
var names [3]string = [3]string{"smile","易文杰","dylan"}
fmt.Println("调用函数之前",names)
changeArray(&names)
fmt.Println("调用函数之后",names)
}
func changeArray(array *[3]string) {
(*array)[0] = "quest"
array[1] = "aron"
}
上面的程序中,数组names的地址传递给函数changeArray在函数中,我们通过解引用的方式将数组的第一个和第二个元素进行重新赋值。程序的输出:
调用函数之前 [smile 易文杰 dylan]
调用函数之后 [quest aron dylan]
array[1]是(*array)[1]`的简写
虽然可以通过传递数组指针给函数的方式来修改原始数组的值,但在Go中不是惯用的方式。我们可以使用切片来完成同样的事情。
采用切片方式重写上面的程序
package main
import "fmt"
func main() {
var names [3]string = [3]string{"smile","易文杰","dylan"}
fmt.Println("调用函数之前",names)
changeArray(names[:])
fmt.Println("调用函数之后",names)
}
func changeArray(array []string) {
array[0] = "quest"
array[1] = "aron"
}
我们将一个切片传递给changeArray函数,在函数内部。切片的第一个和第二个元素被修改。程序的输出为:
调用函数之前 [smile 易文杰 dylan]
调用函数之后 [quest aron dylan]
所以请不要将数组的指针作为参数传递给函数,而是使用切片。这样代码更加简洁,在Go中更常被使用
Go不支持指针运算
package main
import "fmt"
func main() {
var ptr *int
i := 1
ptr = &i
ptr ++
fmt.Println(ptr)
}
上面的程序将会报错:invalid operation: ptr++ (non-numeric type *int)

浙公网安备 33010602011771号