深入探索Go语言中的指针:内存操作的艺术

2024-09-04 03:36

本文主要是介绍深入探索Go语言中的指针:内存操作的艺术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先,尽管指针(pointer)和switch语句在概念上并无直接联系,但本文将它们并置讨论的原因在于:这两个编程概念在实际学习和应用过程中常被编程人员所忽视。

  1. 对于指针的使用,初学者往往因其概念的抽象性和操作的复杂性而产生畏惧,倾向于避免使用或在并发编程中错误地应用,这可能导致严重的数据竞争和同步问题,影响程序的稳定性和安全性。
  2. 另一方面,许多开发者在面对条件分支时,习惯性地依赖if-else语句,而未能充分利用switch语句在处理多条件逻辑时的高效性和清晰性,从而错失了优化代码结构和提升程序性能的机会。

指针pointer

在Go语言中,指针是编程中一个核心的概念,它允许程序直接操作内存地址。虽然Go语言对指针的操作相对简单,主要通过两个符号来实现:

  1. & 操作符用于获取变量的内存地址。当你想要获取一个变量的引用,而不是它的值时,可以使用&来取地址。
  2. * 操作符用于间接引用,也就是通过一个指针来访问和修改它所指向的内存地址上存储的值。

应用

在许多编程语言中,变量是对内存中存储的值的一个命名引用。然而,有时我们可能需要直接操作内存地址,这就需要用到指针。Go语言提供了两种基本的指针操作符号:&用于获取变量的内存地址,而*用于间接引用,即通过指针来访问或修改内存地址上存储的值。

现在,让我们通过一个具体的例子来演示这些操作:

n := 18
// 取地址
fmt.Println(&n)
fmt.Println(*&n)

打印结果如下:

在这里插入图片描述

查询内存地址的类型

当我们获取一个变量的地址时,实际上是创建了一个指针类型的变量,这个指针变量的类型是由它所指向的变量的类型决定的。例如,如果一个指针指向一个int类型的变量,那么这个指针的类型就是*int,即指向int的指针。

现在,让我们通过代码示例来演示如何查询内存地址的类型,并根据这个地址来获取和打印原始变量的值:

p := &n
// 根据地址取值
fmt.Printf("%T\n", p) // 打印结果是*int,即int类型的指针
m := *p
fmt.Println(m) //根据地址取值

打印结果如下:

在这里插入图片描述

我们发现打印的结果是:*int,即int类型的指针。

nil pointer

nil是一个特殊的值,表示指针没有指向任何内存地址。这与C或C++中的空指针概念类似,但Go语言的nil指针更加安全,因为它们不允许进行解引用操作,从而避免了潜在的程序崩溃。当一个指针变量被声明后未初始化,它就是一个nil指针。了解如何声明和识别nil指针,以及如何安全地使用它们,是每个Go程序员的必备技能。

现在,让我们通过代码示例来演示nil指针的使用和转换:

var a1 *int     //nil pointer
fmt.Println(a1) //<nil>var a2 = new(int)
fmt.Println(a2)  //内存地址 0xc000108010
fmt.Println(*a2) //0 根据内存地址取值 没有值返回0*a2 = 100        //根据内存地址赋值
fmt.Println(*a2) //100

打印结果如下:

在这里插入图片描述

总结如下:

在这里插入图片描述

  1. 对变量进行取地址操作(&),可以获得这个变量的指针变量;
  2. 指针变量的值是指针地址(内存地址);
  3. 对指针变量进行取值操作(*),可以获得这个指针变量指向原变量的值,即通过内存地址取值。

switch

我们往往习惯于使用if判断,switch可以简化if判断。

switch的作用和if是一样的,都是进行条件判断,引入switch的原因是能简化我们的if判断,让代码的可读性更强。

可读性更好

举个例子:if判断来判断手指的名称。

finger :=2
if finger==1 {fmt.Println("大拇指")
}else if finger==2 {fmt.Println("食指")
}else if finger==5 {fmt.Println("小拇指")
}else {fmt.Println("无效")
}

switch判断手指名称:

finger := 2
switch finger {
case 1:fmt.Println("大拇指")
case 2:fmt.Println("食指")
case 5:fmt.Println("小拇指")
default:fmt.Println("无效")
}

对比之下立竿剪影:switch case 这种方式可读性更好。

case后支持多个参数

举个例子:奇偶数判断。

switch n := 3; n {
case 1, 3, 5, 7, 9:fmt.Println("奇数")
case 2, 4, 6, 8, 10:fmt.Println("偶数")
}

case后加判断

举个例子:

age := 29
switch {
case age < 18:fmt.Println("好好学习Z")
case age > 18 && age < 60:fmt.Println("好好上班")
case age > 60:fmt.Println("希望不用继续上班了,哈哈")
default:fmt.Println(age)
}

注意:当在case后加判断时,switch后面不需要传入参数,否则会报错:类型不匹配。

在这里插入图片描述

fallthrough

在一个 switch 块内,每个 case 无需声明 break 来终止,如果想顺序执行使用 fallthrough;在一个switch块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。

package mainimport "fmt"func main() {switch {case false:fmt.Println("false1")fallthroughcase true:fmt.Println("true1")fallthroughcase false:fmt.Println("false2")fallthroughcase true:fmt.Println("true2")case false:fmt.Println("false3")fallthroughdefault:fmt.Println("default case")}
}

总结

相信你阅读完这篇文章对Go语言中的指针有了更深刻的理解。至于switch,只要我们心里有这个概念即可:switch作用和if一样,当我们意识到需要写多个if判断时,改用switch实现,往往会是比较好的实践。

这篇关于深入探索Go语言中的指针:内存操作的艺术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134886

相关文章

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Linux内存泄露的原因排查和解决方案(内存管理方法)

《Linux内存泄露的原因排查和解决方案(内存管理方法)》文章主要介绍了运维团队在Linux处理LB服务内存暴涨、内存报警问题的过程,从发现问题、排查原因到制定解决方案,并从中学习了Linux内存管理... 目录一、问题二、排查过程三、解决方案四、内存管理方法1)linux内存寻址2)Linux分页机制3)

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Redis多种内存淘汰策略及配置技巧分享

《Redis多种内存淘汰策略及配置技巧分享》本文介绍了Redis内存满时的淘汰机制,包括内存淘汰机制的概念,Redis提供的8种淘汰策略(如noeviction、volatile-lru等)及其适用场... 目录前言一、什么是 Redis 的内存淘汰机制?二、Redis 内存淘汰策略1. pythonnoe