Go指针探秘:深入理解内存与安全性
目录
- 1. 指针的基础
- 1.1 什么是指针?
- 1.2 内存地址与值的地址
- 1.2.1 内存中的数据存储
- 1.2.2 如何理解值的地址
- 2. Go中的指针操作
- 2.1 指针类型和值
- 2.1.1 基本数据类型的指针
- 2.1.2 复合数据类型的指针
- 2.2 如何获取一个指针值
- 2.3 指针(地址)解引用
- 3. 深入理解指针
- 3.1 我们为什么需要指针?
- 3.1.1 提高程序性能
- 3.1.2 动态数据结构
- 3.1.3 与其他语言的比较
- 3.2 关于"引用"这个术语
- 3.2.1 引用与指针的区别
- 4. Go指针的特性与限制
- 4.1 Go指针的特性
- 4.1.1 零值
- 4.1.2 不支持指针算术
- 4.2 Go指针的限制
- 4.2.1 不支持指针到整数的转换
- 4.2.2 不能获取内建数据类型的地址
- 4.2.3 安全性
- 5. 总结
Go指针为程序员提供了对内存的深入管理能力,同时确保了代码的安全性。本文深入探讨了Go指针的基础概念、操作、深层理解及其特性与限制。通过深入了解其设计哲学和应用,我们可以更好地利用Go的强大功能。
关注TechLead,分享互联网架构、云服务技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。
1. 指针的基础
1.1 什么是指针?
指针是一种变量,其存储的是另一个变量的内存地址,而不是值本身。在很多编程语言中,当我们需要直接访问内存或者希望通过一个变量间接操作另一个变量时,会使用到指针。
示例:
var a int = 42
var p *int = &a
fmt.Println(p) // 打印变量a的内存地址
1.2 内存地址与值的地址
每一个变量都存储在内存中的一个位置上,这个位置被称为该变量的内存地址。而当我们谈论一个变量的地址时,我们实际上是在讨论这个内存地址。
1.2.1 内存中的数据存储
计算机的内存是按照字节(bytes)组织的,每个字节都有一个唯一的地址。一个变量占用的字节数取决于其类型,例如,一个 int
类型在64位系统上通常是8字节。
示例:
var x int64 = 123456789
fmt.Println(&x) // 打印变量x的内存地址
1.2.2 如何理解值的地址
当我们使用&
操作符来获取一个变量的地址时,我们实际上获取的是指向该变量内存起始位置的指针。
示例:
var y string = "OpenAI"
fmt.Println(&y) // 打印变量y的内存地址
在上面的示例中,变量y
存储了字符串"OpenAI",但&y
给我们返回的是这个字符串存储在内存中的地址。
2. Go中的指针操作
2.1 指针类型和值
在Go中,每种数据类型都有与之关联的指针类型。指针类型的定义是前置一个*
到原始数据类型前面。例如,int
的指针类型是*int
。
2.1.1 基本数据类型的指针
示例:
var age int = 30
var agePointer *int = &agefmt.Println(age) // 打印原始变量值:30
fmt.Println(agePointer) // 打印age变量的内存地址
2.1.2 复合数据类型的指针
Go中的复合数据类型(例如slices、maps、channels、arrays、structs)也有其对应的指针类型。
示例:
type Person struct {Name stringAge int
}var person Person = Person{"Alice", 28}
var personPointer *Person = &personfmt.Println(person) // 打印结构体值:{Alice 28}
fmt.Println(personPointer) // 打印结构体的内存地址
2.2 如何获取一个指针值
要获取一个变量的指针值,可以使用&
操作符。
示例:
var fruit string = "apple"
pointerToFruit := &fruitfmt.Println(fruit) // 打印原始值:apple
fmt.Println(pointerToFruit) // 打印fruit的内存地址
2.3 指针(地址)解引用
要获取指针指向的原始值,我们使用*
操作符进行解引用。这允许我们间接地访问和修改指针指向的值。
示例:
var number int = 100
pointerToNumber := &numberfmt.Println(*pointerToNumber) // 通过解引用获取原始值:100// 修改指针指向的值
*pointerToNumber = 200
fmt.Println(number) // 原始变量值被修改为:200
3. 深入理解指针
3.1 我们为什么需要指针?
指针在编程中是一个重要的工具,特别是在需要高性能、灵活性或者对内存使用有严格要求的场景中。
3.1.1 提高程序性能
指针可以减少数据复制的需要,从而提高程序的执行速度。
示例:
考虑一个场景,我们需要交换两个大的数据结构的值。
type LargeStruct struct {Data [1000]int
}func swapWithoutPointer(a, b LargeStruct) {a, b = b, a
}func swapWithPointer(a, b *LargeStruct) {*a, *b = *b, *a
}var x, y LargeStruct
// 使用指针交换
swapWithPointer(&x, &y)
在上面的例子中,使用指针的方法可以避免复制两次大的数据结构,从而更为高效。
3.1.2 动态数据结构
很多动态数据结构(如链表、树、图)都依赖于指针来实现。
示例:
type Node struct {Value intNext *Node
}// 创建链表
first := Node{Value: 1}
second := Node{Value: 2}
third := Node{Value: 3}first.Next = &second
second.Next = &thirdfmt.Println(first.Value) // 1
fmt.Println(first.Next.Value) // 2
3.1.3 与其他语言的比较
与其他一些语言(如C、C++)相比,Go在指针的使用上更为安全。Go不允许进行指针运算,这降低了因为错误操作而导致的程序错误的可能性。
3.2 关于"引用"这个术语
在其他一些编程语言中(如C++、Java),"引用"与"指针"是两个不同的概念,但在Go中,我们主要使用指针,而不是引用。
3.2.1 引用与指针的区别
在某些语言中,引用是一个别名,它表示某个变量。而指针则是一个变量,其值是另一个变量的地址。
示例: 在Go中,我们不使用引用,而是使用指针来实现间接引用。
var original int = 10
pointerToOriginal := &original*pointerToOriginal = 20fmt.Println(original) // 输出:20
在上述示例中,通过指针,我们修改了original
变量的值。
4. Go指针的特性与限制
4.1 Go指针的特性
4.1.1 零值
在Go中,指针的零值是nil
。这意味着如果你声明一个指针变量但没有明确初始化,它的值就是nil
。
示例:
var ptr *int
fmt.Println(ptr == nil) // 输出:true
4.1.2 不支持指针算术
与C和C++不同,Go不支持指针算术操作。这是为了确保更高的内存安全性。
示例:
在C或C++中,你可以做这样的操作:
int arr[10];
int *ptr = &arr[0];
ptr++;
但在Go中,类似的操作是不被允许的。
arr := [10]int{}
ptr := &arr[0]
// ptr++ // 这行会报错,因为Go不支持
4.2 Go指针的限制
4.2.1 不支持指针到整数的转换
在某些低级编程环境中,你可能需要将指针转换为整数进行某些操作,或者反之。但在Go中,这样的操作是不允许的,以确保程序的安全性和可读性。
4.2.2 不能获取内建数据类型的地址
在Go中,例如对于切片的元素或map的值,我们不能直接获取其地址。
示例:
m := map[string]int{"Alice": 25}
// ptr := &m["Alice"] // 这行会报错
4.2.3 安全性
Go的设计者们故意限制了指针的某些能力,以提高程序的安全性。例如,你不能在Go中进行指针算术,也不能随意地将指针与整数之间进行转换。
5. 总结
Go语言为现代编程提供了一种独特的途径。它不仅结合了经典的C风格语法,还引入了一系列新颖的设计哲学。这其中,Go对指针的处理尤为出色,它既维护了指针的功能性,又增强了代码的安全性。
深入的内存管理: Go语言通过指针让开发者有机会深入了解和管理内存。与直接操作值相比,指针为数据操作带来了更大的灵活性,特别是在处理大型数据结构或希望避免数据复制时。
安全性与简洁性的权衡: 通过消除指针算术和严格的类型限制,Go确保了程序员在操作指针时的安全性。这种设计选择可能限制了某些低级操作的能力,但它大大降低了因为误用指针而导致的程序错误的风险。
高级与低级的结合: 尽管Go提供了高级的数据结构如切片、映射等,但它仍然允许程序员通过指针进行低级的内存操作。这为开发者提供了无与伦比的灵活性,使他们既可以编写高性能的代码,又不失代码的可读性和可维护性。
关注TechLead,分享互联网架构、云服务技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。
相关文章:

Go指针探秘:深入理解内存与安全性
目录 1. 指针的基础1.1 什么是指针?1.2 内存地址与值的地址1.2.1 内存中的数据存储1.2.2 如何理解值的地址 2. Go中的指针操作2.1 指针类型和值2.1.1 基本数据类型的指针2.1.2 复合数据类型的指针 2.2 如何获取一个指针值2.3 指针(地址)解引用…...

Oracle12c之Sqlplus命令行窗口基本使用
Oracle12c之Sqlplus命令行窗口基本使用 文章目录 Oracle12c之Sqlplus命令行窗口基本使用1. 连接1. 超级用户2. 普通用户1. 创建普通用2. 连接 2. 修改用户连接数1. 查看默认连接最多用户数1. PL/SQL developer中查看2. Sqlplus中查看 2. 查看目前已经连接的用户数3. 修改用户连…...

react和antd学习笔记
概论 react是前端框架,antd是组件库。前端框架和组件库的区别与联系 nodejs 脚本语言需要一个解析器才能运行,JavaScript是脚本语言,在不同的位置有不一样的解析器,如写入html的js语言,浏览器是它的解析器角色。而对…...
寒假作业2月5号
第四章 堆与拷贝构造函数 一 、程序阅读题 1、给出下面程序输出结果。 #include <iostream.h> class example {int a; public: example(int b5){ab;} void print(){aa1;cout <<a<<"";} void print()const {cout<<a<<endl;} …...
滑动窗口(一)
文章目录 Leetcode209. 长度最小的子数组题目解法一(暴力求解)(超时)解法二(滑动窗口) Leetcode3. 无重复字符的最长子串题目解法一(暴力求解)解法二(滑动窗口) Leetcode1004. 最大连…...

寒假 day1
1、请简述栈区和堆区的区别? 2、有一个整形数组:int arr[](数组的值由外部输入决定),一个整型变量: x(也 由外部输入决定)。要求: 1)删除数组中与x的值相等的元素 2)不得创建新的数组 3)最多只允许使用单层循环 4)无需考虑超出新数组长度后面的元素,所以…...

DATAX改造支持geometry类型数据同步
数据库使用postgresql安装了postgis插件存储了geometry空间数据,想使用datax做数据同步,但datax本身不支持geometry类型数据,如何改造呢? 1.首先下载已改造支持geometry类型的datax引擎,下载地址 https://download.c…...

Vue中keep-alive的作用、原理及应用场景
在进行Vue开发的过程中,我们经常会遇到需要进行组件缓存的场景,这时候Vue提供的keep-alive组件就派上了用场。keep-alive组件是Vue内置的一个抽象组件,它可以将其包裹的组件进行缓存,提高组件的性能,同时也可以节省服务…...
SpringBoot集成Redisson实现限流(二)
1. 简介 Springboot集成Redisson默认的限流器为令牌桶型限流器,底层是通过lua脚本去实现的。 通过lua脚本我们可以去实现一个滑动窗口限流器,利用ZSET格式数据就可以轻松实现。 springboot集成Redisson就不做讲解,可以参考:sprin…...

【2024美赛E题】985博士解题思路分析(持续更新中)!
【2024美赛E题】985博士解题思路分析! 加群可以享受定制等更多服务,或者搜索B站:数模洛凌寺 联络组织企鹅:936670395 以下是E题老师的解题思路(企鹅内还会随时更新文档): 2024美赛E题思路详解…...

北朝隋唐文物展亮相广西,文物预防性保护网关保驾护航
一、霸府名都——太原博物馆收藏北朝隋朝文物展 2月1日,广西民族博物馆与太原博物馆携手,盛大开启“霸府名都——太原博物馆北朝隋文物展”。此次新春展览精选了北朝隋唐时期150多件晋阳文物珍品。依据“巍巍雄镇”“惊世古冢”“锦绣名都”三个单元&am…...

回归预测 | Matlab实现WOA-CNN-LSTM-Attention鲸鱼算法优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制)
回归预测 | Matlab实现WOA-CNN-LSTM-Attention鲸鱼算法优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制) 目录 回归预测 | Matlab实现WOA-CNN-LSTM-Attention鲸鱼算法优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制&…...

ubuntu离线安装k8s
目录 一、前期准备 二、安装前配置 三、安装docker 四、安装cri-dockerd 五、部署k8s master节点 六、整合kubectl与cri-dockerd 七、网络等插件安装 八、常见问题及解决方法 一、前期准备 ①ubuntu系统 本地已安装ubuntu系统,lsb_release -a命令查看版本信…...

学成在线:媒体资源管理系统(MAM)
媒体资源管理系统(MAM) 媒体资源管理系统(Media Asset Management)是建立在多媒体、网络、数据库和数字存储等先进技术基础上的一个对各种媒体及内容进行数字化存储、管理以及应用的总体解决方案,可以满足媒体资源拥有者收集、保存、查找、编辑、发布各种信息的要求,为媒体资源…...
18个8年以上服务器开发经验的面试题(2)
目录 1.问:如何设计一个系统来确保在可能出现网络分区和故障的分布式环境中的数据一致性?...
【SpringBoot】applicationContext.getBeansOfType(class)获取某一接口所有实现类,应用于策略模式
一、问题的提出 在实际工作中,我们经常会遇到一个接口及多个实现类的情况,并且在不同的条件下会使用不同的实现类。 二、应用场景 springboot 项目中通过 ApplicationContext.getBeansOfType(class) 获取某一接口的所有实现类,并通过枚举完…...

AJAX-入门
定义 概念:AJAX是浏览器与服务器进行数据通信的技术 使用 1.先使用axios库,与服务器进行数据通信 1)基于XMLHttpRequest封装、代码简单、月下载量在14亿次 2)Vue、React项目中都会用到axios 2.再学习XMLHttpRequest对象的使用…...
学术写作|第二篇论文写作记录|GPT4论文润色Prompt
本文目录 写作时间安排如何写出初稿?找谁修改?1. 找AI修改2. 找师姐、师兄、老师、同行/外行修改论文修改意见集锦(反复观看)最好用的GPT4指令禁止转载,未经允许的任何引用。 写作时间安排 第二篇工作的idea去年就想出来了,一直被其他事情干扰,错过了N个会议… 在寒假…...

力扣热门100题刷题笔记 - 10. 正则表达式匹配
力扣热门100题 - 10. 正则表达式匹配 题目链接:10. 正则表达式匹配 题目描述: 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配ÿ…...

4.0 HDFS 配置与使用
之前提到过的 Hadoop 三种模式:单机模式、伪集群模式和集群模式。 单机模式:Hadoop 仅作为库存在,可以在单计算机上执行 MapReduce 任务,仅用于开发者搭建学习和试验环境。 伪集群模式:此模式 Hadoop 将以守护进程的…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...