我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Rust语言中级教程之指针

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Rust语言中级教程之指针

Rust语言中级教程

一、指针

什么是指针

  • 指针是计算机引用无法立即直接访问的数据的一种方式(类比 书的目录)
  • 数据在物理内存(RAM)中是分散的存储着
  • 地址空间是检索系统
  • 指针就被编码为内存地址,使用 usize 类型的整数表示。
    • 一个地址就会指向地址空间中的某个地方
  • 地址空间的范围是 OS 和 CPU 提供的外观界面
    • 程序只知道有序的字节序列,不会考虑系统中实际 RAM 的数量

名词解释

  • 内存地址(地址),就是指代内存中单个字节的一个数
    • 内存地址是汇编语言提供的抽象
  • 指针(有时扩展称为原始指针),就是指向某种类型的一个内存地址
    • 指针是高级语言提供的抽象
  • 引用,就是指针。如果是动态大小的类型,就是指针和具有额外保证的一个整数
    • 引用是 Rust 提供的抽象

Rust 的引用

  • 引用始终引用的是有效数据
  • 引用与 usize 的倍数对齐
  • 引用可以为动态大小的类型提供上述保障

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 = 42;
    let b = &B;
    let c = &C;
    println!("a: {}, b: {:p}, c: {:p}", a, b, c);
}

运行

point_demo on  master [?] is ? 0.1.0 via ? 1.67.1 via ? base 
➜ cargo run           
   Compiling point_demo v0.1.0 (/Users/qiaopengjun/rust/point_demo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.44s
     Running `target/debug/point_demo`
a: 42, b: 0x1023dc660, c: 0x1023dc66a

point_demo on  master [?] is ? 0.1.0 via ? 1.67.1 via ? base 
➜ 

  • 一个更加逼真的例子
    • 使用更复杂的类型展示指针内部的区别
use std::mem::size_of;
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 = 42;
    // let b = &B;
    // let c = &C;
    // println!("a: {}, b: {:p}, c: {:p}", a, b, c);
    let a: usize = 42;
    let b: Box<[u8]> = Box::new(B);
    let c: &[u8; 11] = &C;
    println!("a (unsigned 整数):");
    println!("  地址: {:p}", &a);
    println!("  大小:    {:?} bytes", size_of::<usize>());
    println!("  值:  {:?}\n", a);
    println!("b (B 装在 Box 里):");
    println!("  地址:  {:p}", &b);
    println!("  大小:    {:?} bytes", size_of::<Box<[u8]>>());
    println!("  指向:  {:p}\n", b);
    println!("c (C 的引用):");
    println!("  地址:  {:p}", &c);
    println!("  大小:  {:?} bytes", size_of::<&[u8; 11]>());
    println!("  指向:  {:p}\n", c);
    println!("B (10 bytes 的数组):");
    println!("  地址:  {:p}", &B);
    println!("  大小:  {:?} bytes", size_of::<[u8; 10]>());
    println!("  值:  {:?}\n", B);
    println!("C (11 bytes 的数字):");
    println!("  地址:  {:p}", &C);
    println!("  大小:  {:?} bytes", size_of::<[u8; 11]>());
    println!("  值:  {:?}\n", C);
}

运行

point_demo on  master [?] is ? 0.1.0 via ? 1.67.1 via ? base 
➜ cargo run
   Compiling point_demo v0.1.0 (/Users/qiaopengjun/rust/point_demo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/point_demo`
a (unsigned 整数):
  地址: 0x16dda9a08
  大小:    8 bytes
  值:  42

b (B 装在 Box 里):
  地址:  0x16dda9a10
  大小:    16 bytes
  指向:  0x12b606ba0

c (C 的引用):
  地址:  0x16dda9a30
  大小:  8 bytes
  指向:  0x10208d7ba

B (10 bytes 的数组):
  地址:  0x10208d7b0
  大小:  10 bytes
  值:  [99, 97, 114, 114, 121, 116, 111, 119, 101, 108]

C (11 bytes 的数字):
  地址:  0x10208d7ba
  大小:  11 bytes
  值:  [116, 104, 97, 110, 107, 115, 102, 105, 115, 104, 0]

point_demo on  master [?] is ? 0.1.0 via ? 1.67.1 via ? base 
➜ 

  • 对 B 和 C 中文本进行解码的例子
    • 它创建了一个与前图更加相似的内存地址布局
use std::borrow::Cow;
use std::ffi::CStr;
use std::os::raw::c_char;
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 = 42;
  let b: String;
  let c: Cow<str>;
  unsafe {
    let b_ptr = &B as * const u8 as *mut u8;
    b = String::from_raw_parts(b_ptr, 10, 10);
    let c_ptr = &C as *const u8 as *const c_char;
    c = CStr::from_ptr(c_ptr).to_string_lossy();
  }
  println!("a: {}, b: {}, c: {}", a, b, c);
}

Raw Pointers(原始指针)

  • Raw Pointer (原始指针)是没有 Rust 标准保障的内存地址。
    • 这些本质上是 unsafe 的
  • 语法:
    • 不可变 Raw Pointer:*const T
    • 可变的 Raw Pointer:*mut T
    • 注意:*const T,这三个标记放在一起表示的是一个类型
    • 例子:*const String
  • *const T 与 *mut T 之间的差异很小,相互可以自由转换
  • Rust 的引用(&mut T 和 &T)会编译为原始指针
    • 这意味着无需冒险进入 unsafe 块,就可以获得原始指针的性能
  • 例子:把引用转为原始指针
fn main() {
  let a: i64 = 42;
  let a_ptr = &a as *const i64;
  println!("a: {} ({:p})", a, a_ptr);
}
  • 解引用(dereference):通过指针从 RAM 内存提取数据的过程叫做对指针进行解引用(dereferencing a pointer)
  • 例子:把引用转为原始指针
fn main() {
  let a: i64 = 42;
  let a_ptr = &a as *const i64;
  let a_addr: usize = unsafe {std::mem::transmute(a_ptr)};
  println!("a: {} ({:p}...0x{:x})", a, a_ptr, a_addr + 7);
}

关于 Raw Pointer 的提醒

  • 在底层,引用(&T 和 &mutT)被实现为原始指针。但引用带有额外的保障,应该始终作为首选使用
  • 访问 Raw Pointer 的值总是 unsafe 的
  • Raw Pointer 不拥有值的所有权
    • 在访问时编译器不会检查数据的合法性
  • 允许多个 Raw Pointer 指向同一数据
    • Rust 无法保证共享数据的合法性

使用 Raw Pointer 的情况

  • 不可避免
    • 某些 OS 或 第三方库需要使用,例如与C交互
  • 共享对某些内容的访问至关重要,运行时性能要求高

Rust 指针生态

  • Raw Pointer 是 unsafe 的
  • Smart Pointer(智能指针)倾向于包装原始指针,附加更多的能力
    • 不仅仅是对内存地址解引用

Rust 智能指针

名称简介强项弱项
Raw Pointer*mut T 和 *const T,自由基,闪电般块,极其 Unsafe速度、与外界交互Unsafe
Box<T>可把任何东西都放在Box里。可接受几乎任何类型的长期存储。新的安全编程时代的主力军。将值集中存储在 Heap大小增加
Rc<T>是Rust的能干而吝啬的簿记员。它知道谁借了什么,何时借了什么对值的共享访问大小增加;运行时成本;线程不安全
Arc<T>是Rust的大使。它可以跨线程共享值,保证这些值不会相互干扰对值的共享访问;线程安全大小增加;运行时成本
Cell<T>变态专家,具有改变不可变值的能力内部可变性大小增加;性能
RefCell<T>对不可变引用执行改变,但有代价内部可变性;可与仅接受不可变引用的Rc、Arc嵌套使用大小增加;运行时成本;缺乏编译时保障
Cow<T>封闭并提供对借用数据的不可变访问,并在需要修改或所有权时延迟克隆数据当只是只读访问时避免写入大小可能会增大
String可处理可变长度的文本,展示了如何构建安全的抽象动态按需增长;在运行时保证正确编码过度分配内存大小
Vec<T>程序最常用的存储系统;它在创建和销毁值时保持数据有序动态按需增长过度分配内存大小
RawVec<T>Vec<T>和其它动态大小类型的基石;知道如何按需给你的数据提供一个家动态按需增长;与内存分配器一起配合寻找空间不直接适用于您的代码
Unique<T>作为值的唯一所有者,可保证拥有完全控制权需要独占值的类型(如 String)的基础不适合直接用于应用程序代码
Shared<T>分享所有权很难,但他使生活更轻松共享所有权;可以将内存与T的宽度对齐,即使是空的时候不适合直接用于应用程序代码

到此这篇关于Rust语言中级教程之指针的文章就介绍到这了,更多相关Rust指针内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Rust语言中级教程之指针

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Rust语言中级教程之指针

Rust中共有三种类型的指针,分别为引用,解引用,智能指针,这篇文章主要介绍了Rust语言中级教程之指针,需要的朋友可以参考下
2023-05-19

C语言中如何实现二级指针

今天小编给大家分享一下C语言中如何实现二级指针的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。C语言中二级指针的实例详解用图说
2023-06-17

C语言中二级指针与链表怎么应用

本文小编为大家详细介绍“C语言中二级指针与链表怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言中二级指针与链表怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。二级指针讲解简述:其实就是一个指针
2023-07-02

C语言高级教程之变长数组详解

这篇文章主要介绍了C语言中变长数组的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-02-06

C语言中数组和指针,内存之间的关系是什么

小编给大家分享一下C语言中数组和指针,内存之间的关系是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先论证一维数组和一级指针之前的关系,我们常常使用一级指针
2023-06-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录