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

内存图:

go语言struct 指针 golang中的指针运算包括_go语言struct 指针

如果改变*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{}