当前位置: 首页 > news >正文

【Rust中级教程】1.1. 指针概览(上):什么是指针、指针和引用的区别

1.1 指针概览(上):什么是指针、指针和引用的区别

1.1.1. 什么是指针

指针是计算机引用无法立即直接访问的数据的一种方式。

一个非常形象的类比就是书的目录,目录相当于指针,目录里面存的是对应内容所在的页码;在计算机中,指针存的是一个地址。在书里面我们通过目录的页码就可以找到具体的内容,在计算机里,我们通过指针里存的地址来找到我们想要访问的数据。下图是对指针一个形象的描述图:

数据在物理内存中(Random Access Memory,简称RAM)是分散着存储的。而为了找到具体的数据,我们需要一个检索系统,叫做地址空间

指针会被编码为内存地址,使用usize类型(使用usize的原因在讲虚拟内存时会讲)的整数表示。一个地址会指向地址空间中的某个地方。

地址空间的范围是系统和CPU提供的外观界面(facade,指个系统或组件对外呈现的简化界面,隐藏了复杂的内部细节)。程序只知道有序的字节序列,并不会考虑系统中实际RAM的数量。

1.1.2. 名词解释

  • 内存地址(又叫地址):内存中指代单个字节的一个数。内存地址是汇编语言提供的抽象。
  • 指针(又叫原始指针):指向某种类型的一个内存地址。指针是高级语言提供的抽象。
  • 引用:这里的引用指的是Rust中的引用(详见 4.4. 引用与借用)。它就是指针,但如果它指向的数据是动态大小的类型(比如str[T]),那么引用会提供一个整数来保证知道数据的边界在哪里以防止越界。引用是Rust语言提供的抽象。

1.1.3. Rust中的引用

Rust的引用相比于原始指针有很多的好处:
- 引用始终引用的是有效的数据

  • 引用与usize的倍数是对齐的,如果不对齐CPU的操作就会变慢。Rust通过填充字节来保证引用能在内存上对齐。
    对齐(Alignment)是指数据在内存中的存储地址必须是某个特定数值的倍数,以满足硬件的访问要求并提高效率。在Rust中,引用(如&T&mut T)的地址总是对齐到usize的倍数,这意味着它的起始地址是系统字长(例如32位系统为4字节,64位系统为8字节)的整数倍。例如,在64位系统中,如果一个变量的地址是0x1001,它不是8的倍数,因此不能作为引用的地址;而0x10000x1008则是有效的引用地址。

  • 引用可为动态大小的类型提供上述的保障。对于在内存中没有固定长度的类型,Rust会保证它的长度会被保存在内部指针的路径,这样就能知道知道数据的边界在哪里以防止越界。

1.1.4. Rust的引用和指针

看个例子:

static B: [u8; 10] = [99, 97, 114, 114, 121, 116, 111, 119, 101, 108]; static C: [u8; 11] = [116, 104, 97, 110, 107, 115, 102, 105, 115, 104, 0]; fn main() { let a:i32 = 42; let b:&[u8;10] = &B; let c:&[u8;11] = &C; println!("a = {}, b = {:p}, c = {:p}", a, b, c); }
  • bB的引用,cC的引用
  • {:p}指的是打印出变量的内存地址

输出:

a = 42, b = 0x1021d97e0, c = 0x1021d97ea

abc在内存空间中的局部视图如下:

  • 变量bc是引用,在32位CPU上占4字节,在64位上占8字节(这里是4字节)
  • ai32类型,所以在内存上占4字节
  • 静态变量BC是两个数组,数组里的元素是u8,所以每个元素只占1字节

这这个代码想要实现的是b模拟智能指针,c模拟原始指针。这个例子还模拟得不够接近,后续会有更逼真的例子,现在就将就着吧。

这是一个我们虚构的拥有49个字节的地址空间,表示的是我们最终想要达到的效果,所以会和上文的代码有出入。我们一点一点来解析:
-a是一个整数,但由于图是我们假想的理想情况,所以说图里的类型是i16(占2字节),不是原来的i32
-b是一个智能指针,总长度是4字节,地址字段的长度只占2字节,也就是u16。长度字段占2字节,由于B是有10个元素的数组,所以在长度字段存储的值就是10。地址字段存储的32表示数据所在的起始位置,也就是0x20(32用16进制表示就是0x20)这个地方,长度是10,所以就是从0x20到0x29这块数据
-c是一个原始指针,占2个字节,字节里存的就是地址。这里存的是16,换成16进制就是0x10,所以c指向的数据从0x10开始,里面有11个元素,所以指向的是0x10到0x1A的数据块。
- 0x0是空字节(NULL byte),是程序的死区。如果指针指向这个地方再进行解引用就会崩溃。

其他知识:
- 变量c是以0结尾的buffer,其实这是C语言中字符串的内部表示形式(C语言中的字符串是一个数组,以0结尾)。了解如何将这些类型转化为Rust中的类型对于通过外部函数接口(Foreign Function Interface,简称FFI,后面会详细地讲)处理外部代码是非常有用的。
- 变量cC在一起就叫做Rust里的CStr类型
- 变量b实际上是一个长度为10,固定长度的buffer,但这个buffer不带终止符(不以0结尾)。当这个buffer在指针类型后面使用时会被称作后备数组
- 变量bB在一起几乎可以创建出Rust中的字符串类型,但字符串类型还包含一个容量(capacity)字段。也就是说,组成Rust字符串类型需要长度、地址和容量三个字段。

http://www.jsqmd.com/news/1256567/

相关文章:

  • 【研发类-前端开发Skills】antigravity-design-expert 技能
  • WeChatExporter终极指南:如何免费永久备份微信聊天记录
  • 抖音直播录制神器:轻松保存40+平台直播内容的完整指南
  • 【Rust中级教程】2.10. API设计原则之受约束性(constrained) Pt.1:对类型进行修改、`#[non_exhaustive]`注解
  • 2026 年当下,湖州有实力的衣橱整理收纳培训供货商哪个好,扔掉后悔!衣橱焕新自救指南-娘子帮母婴 - 品质体验官
  • 目标检测:视觉系统中的CNN-Transformer融合网络
  • Python基础5-18
  • python元组知识点
  • 游戏客服响应效率提升300%:揭秘头部厂商AI机器人背后的真实训练数据与对话引擎架构
  • 抖音下载神器:如何用免费工具一键批量下载无水印视频?
  • 5大核心技术构建高效抢票自动化系统:从原理到实战的完整指南
  • AI数字人直播月入10万+的5个真实案例:从零搭建到稳定变现的全流程拆解
  • 阿拉善出发西藏年度口碑榜:2026纯玩小团冠军揭晓,这家15年地接社凭什么?| 附:旅行社电话 - 西藏康泰旅行社
  • Three.js 城市混合Shader教程
  • 3步解锁网易云音乐NCM文件:ncmdumpGUI完整使用指南
  • Micrometer 系列【4】入门案例
  • Python 项目配置管理:用 pydantic-settings 管理 RAG 服务的多环境配置
  • 如何彻底移除Windows Defender:系统管理员终极指南与性能优化工具
  • day8
  • 电瓶车托运专线物流哪家靠谱?慧寄侠整车直发不拆电池260元起 - 快递物流资讯
  • svn背景颜色和符号,图解详细说明
  • 03-Kmeans-顾客数据聚类分析
  • Linux调试方法
  • 【MQTT】paho.mqtt.c 库的“介绍、下载、交叉编译” 详解,以及编写MQTT客户端例子源码
  • 抖音下载神器:如何一键批量下载无水印视频的完整指南
  • springboot民宿预约管理系统---附源码42075
  • 2026 年海晏专业的消防专用防冻液公司联系方式,零下30℃天里,消防官兵靠啥守住供水生命线?这玩意儿比普通防冻液靠谱10倍 - 企业推荐官【认证官方】
  • 【Rust中级教程】2.9. API设计原则之显然性(obvious) :文档与类型系统、语义化类型、使用“零大小”类型
  • 鸿蒙 PC Markdown 编辑器系统剪贴板权限与中文回归
  • 零基础5分钟搭建:如何用daily_stock_analysis实现A股智能分析