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

结合程序,画出内存示意图如下:

image-20211204220800003

在上图中,变量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)

原文地址:https://www.cnblogs.com/ywjcqq/p/15656554.html