【Go语言】深入解读Go语言中的指针,助你拨开迷雾见月明

news/2024/9/28 4:38:22/

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

在这里插入图片描述

文章目录

Go语言中的指针

在Go语言中,指针是一种特殊的变量类型,它用于存储变量的内存地址。通过指针,程序可以直接访问和修改变量的值,这在处理大型数据结构、优化内存使用和提高程序性能时非常有用。本文将结合具体案例,详细讲解Go语言中指针的用法,包括定义指针、使用指针访问和修改变量值、指针作为函数参数和返回值、指针数组和切片、结构体指针、空指针检查等。

一、指针的基本概念

指针是指向内存地址的变量。在Go语言中,使用*操作符来声明一个指针变量。例如:

var p *int // 声明一个指向int型变量的指针

这里p是一个整型指针,它存储的是一个整型变量的内存地址。

1. 获取变量的地址

通过在变量名前加上&符号,可以获取变量的内存地址。例如:

var x int = 10
var p *int = &x // p存储了x的地址

2. 访问指针指向的值

通过在指针变量前加上*符号,可以访问指针指向的值。例如:

fmt.Println(*p) // 输出指针p指向的值,即变量x的值

二、指针的基本用法

1. 定义指针

在Go语言中,使用*操作符定义指针变量。例如:

package mainimport "fmt"func main() {var x int = 42var p *int = &x // 定义一个int类型的指针变量p,并将x的地址赋值给p//获取指针指向的地址中存的值fmt.Println(*p)
}

在这里插入图片描述

2. 使用new函数创建指针

new函数用于创建一个指定类型的零值指针变量。例如:

p := new(int) // 创建一个int类型的零值指针变量
*p = 42 // 通过指针设置值
fmt.Println("Value stored in p:", *p)

在这里插入图片描述

3. 指针作为函数参数

指针作为函数参数,可以在函数内部修改原始变量的值,从而避免函数对变量进行拷贝,提高程序的性能。例如:

func changeValue(a *int) {*a = 20
}func main() {x := 10fmt.Println("Before:", x)changeValue(&x)fmt.Println("After:", x)
}

输出结果为:

Before: 10
After: 20

这表明我们通过指针修改了x的值。

4. 指针作为函数返回值

函数可以返回指针类型的值,以便在函数外部访问函数内部创建的变量。

package mainimport "fmt"// 指针函数, 指针是可以用作函数的返回值
func main() {// 调用了这个函数后,可以得到一个指针类型的变量。ptr := f5()//内存地址正常打印前面带个&fmt.Println("ptr:", ptr)fmt.Printf("ptr:%p\n", ptr)fmt.Printf("ptr类型:%T\n", ptr)fmt.Println("ptr的地址:", &ptr)fmt.Println("ptr地址中的值:", *ptr)// 使用fmt.Println((*ptr)[0])ptr[0] = 10fmt.Println(ptr[0])}// 调用该函数后返回一个指针,此时返回个数组指针
func f5() *[4]int {arr := [4]int{1, 2, 3, 4}//内存地址往往被赋值给指针return &arr}

在这里插入图片描述

5. 空指针检查

在使用指针之前,应该进行空指针检查,以避免出现空指针引用的错误。可以使用nil值来表示空指针。例如:

package mainimport "fmt"func main() {var p *int // 声明一个int类型的指针变量,默认值为nilif p != nil {fmt.Println(*p) // 对非空指针进行操作} else {fmt.Println("Pointer is nil")}
}

在这里插入图片描述

三、指针的高级用法

1. 指针数组和指针切片

指针数组和指针切片允许我们存储多个指针变量,并通过这些指针访问和修改对应的值。

指针数组
package mainimport "fmt"func main() {a := 1b := 2c := 3d := 4// 创建一个指针数组arr1 := [4]*int{&a, &b, &c, &d}fmt.Println(arr1)// 通过指针修改a的值// arr1[0] 0xc00000e0a8*arr1[0] = 100fmt.Println(a)a = 200fmt.Println(*arr1[0])
}

在这里插入图片描述

指针切片
slice := []int{4, 5, 6}
var pSlice *[]int = &slice
fmt.Println("Pointer to Slice:", *pSlice)

2. 数组指针

数组指针,首先应该是一个指针,指向了一个数组

package mainimport "fmt"// 数组指针
func main() {// 创建数组,值传递。funarr1 := [4]int{1, 2, 3, 4}fmt.Println("arr1:", arr1)fmt.Printf("arr1指向的地址:%p\n", &arr1)// 创建一个指针,指向这个数组的地址,通过指针来操作数组//var p1 *[4]int//创建指针方法二p1 := new([4]int)p1 = &arr1fmt.Printf("p1指向的地址: %p\n", p1)fmt.Printf("p1自己的地址: %p\n", &p1)fmt.Println("p1指向的地址的值: ", *p1)fmt.Printf("p1指向的地址的值: %v\n", *p1)// 操作数组指针 来修改数组(*p1)[0] = 100 // 原生写法fmt.Println("arr1:", arr1)fmt.Println("p1指向的地址的值: ", *p1)// 语法糖:由于p1指向了arr1这个数组,所以可以直接用p1来操控数组// 指向了谁,这个指针就可以代表谁。// p1 = arr1p1[0] = 200 // 在程序中,我们更多时候是这样在使用指针fmt.Println("arr1:", arr1)fmt.Println("p1指向的地址的值: ", *p1)}

在这里插入图片描述

3. 指针和切片

在Go语言中,切片本身就是通过指针引用的,因此修改切片元素的值也会影响到原始数组。但是,当重新分配切片时(例如使用append函数),切片的底层数组可能会改变,此时原有的切片指针将不再指向新的底层数组。

func modifySlice(s *[]int) {(*s)[0] = 99*s = append(*s, 100)
}func main() {slice := []int{1, 2, 3}fmt.Println("Original Slice:", slice)modifySlice(&slice)fmt.Println("Modified Slice:", slice)
}

4. 指针和方法

在Go语言中,方法的接收者可以是值类型或指针类型。使用指针作为接收者可以减少数据拷贝,提高性能,特别是当处理大型结构体时。

type Rectangle struct {Width  intHeight int
}func (r *Rectangle) Area() int {return r.Width * r.Height
}func main() {rect := Rectangle{Width: 5, Height: 10}fmt.Println("Area:", rect.Area())
}

5. 接口中的指针

在Go语言中,接口是一种类型,它定义了对象的行为。当接口的实现是大型结构体时,使用指针作为接口的实现可以减少数据拷贝,提高性能。

type Shape interface {Area() float64
}type Circle struct {Radius float64
}func (c *Circle) Area() float64 {return math.Pi * c.Radius * c.Radius
}func printArea(s Shape) {fmt.Println("Area:", s.Area())
}func main() {circle := Circle{Radius: 5}printArea(&circle) // 注意这里传递的是&circle,因为Circle的Area方法接收的是指针
}

注意:在上面的printArea函数调用中,我们传递了&circle而不是circle,因为CircleArea方法接收的是*Circle类型的参数。

6. 指针指针

指针的套娃,指针指向指针 , 指针类型 第一个*指针类型, *int是这个指针对应的类型。
如何理解多个符号,第一个取出来后,后面就是它存的类型 *(*(int))

package mainimport "fmt"func main() {// 声明 普通变量var a int = 10// 声明 指针变量,指向a, 指针其实就是一个特殊的变量而已。,ptr命名  p// 定义变量格式  var ptr *类型var p *intp = &a // 指针变量赋值// 指针的套娃,指针指向指针 , 指针类型 第一个*指针类型, *int是这个指针对应的类型// 如何理解多个符号,第一个取出来后,后面就是它存的类型 *(*(int))var ptr **intptr = &p//fmt.Printf("ptr变量存储的指针的地址:%p\n", ptr) //就是p的地址fmt.Printf("ptr变量自己的地址:%p\n", &ptr)fmt.Printf("*ptr变量存储的地址:%p\n", *ptr)     //就是p存的指针的地址fmt.Printf("*ptr变量存储的地址中的值:%d\n", **ptr) //就是p存的指针的地址指向的值,即是a的值// 修改变量a就有了无数种方式**ptr = 1111fmt.Println(a)
}

在这里插入图片描述

四、总结

指针在Go语言中是一种非常强大的工具,它允许我们直接访问和修改内存中的值,优化内存使用和提高程序性能。然而,过度使用指针也可能导致代码难以理解和维护,还可能引发内存泄漏和悬空指针等问题。因此,在使用指针时要谨慎,并遵循Go语言的指针使用规范。

通过本文的详细讲解和具体案例,相信读者已经对Go语言中的指针有了更深入的了解。在实际开发中,可以根据项目需求,在合适的场景中使用指针来优化程序性能。


http://www.ppmy.cn/news/1531445.html

相关文章

虚拟机文件系统根目录上的磁盘空间不足?VMware虚拟机扩容磁盘步骤讲解

VMware虚拟机扩容磁盘步骤讲解 今天使用vmware,想使用Ubuntu虚拟机,结果出现这种情况: 我的环境: Ubuntu20.04 VMWare workstation pro 17 VMware设置 参考链接: https://blog.csdn.net/hktkfly6/article/details…

Sqlite_Datetime列选择三月的行

In SQLite, use the strftime function to extract components from a date/time value SELECT * FROM table WHERE strftime(%m, datemonth) 03;strftime(‘%m’, datemonth): extracts the month part from the datemonth column as a string (with leading zeros for sing…

50道渗透测试面试题,全懂绝对是高手

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330&scene21#wechat_redirect 《网安面试指南》…

Unity图形用户界面!*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。(万字解析)

Unity 3D GUI 简介 游戏开发过程中,开发人员往往会通过制作大量的图形用户界面( Graphical User Interface,GUI )来增强游戏与玩家的交互性。 Unity 3D 中的图形系统分为 OnGUI、NGUI、UGUI等,这些类型的图形系统内容…

国产数据库盘点-亚信安慧AntDB独立模式部署

本章节主要介绍 AntDB 集中式独立模式部署,主要分两步: 安装数据库(二进制文件) 数据库初始化 安装数据库 以 AntDB 7.2 版本的安装包 antdb-t-ee-release-7.2.generic.* 举例。 将安装包(antdb-t-ee-release-7.2…

【C++】模板、宏、命名空间、

十五、C中的模板templates 本部分讨论C中的模板templates 在别的语言中,比如java、c、c#等托管语言中,模板类似泛型的概念,但模板比泛型要强大得多。模板有点像宏,而泛型却非常受限于类型系统以及其他很多因素。同时模板也是一个…

postman发送与返回,GET与POST使用

1.GET 获取主页 发送: uri: ‘/’ 返回: 2.POST 发送密码 发送: uri: ‘/login.html’ 返回: 3.POST 保存参数 发送: 返回: 4.GET 获取参数 在POST密码之后,服务器发送一个H…

Spring Boot自定义配置项

Spring Boot自定义配置项 配置文件 在application.properties文件添加需要的配置 比如: file.pathD:\\flies\\springboot\\ConfigurationProperties 注解 使用注解ConfigurationProperties将配置项和实体Bean关联起来,实现配置项和实体类字段的关联&…