热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Rust中的指针:Box、Rc、Cell、RefCell

Rust中的指针:Box、Rc、Cell、RefCell作者:许野平2022-02-21Rust自身具有&、*操作符,可以实现变量引用
Rust 中的指针:Box、Rc、Cell、RefCell

作者:许野平 2022-02-21

Rust 自身具有 &、* 操作符,可以实现变量引用和解引用。为什么又搞出这几个类型的指针呢?原因就是想突破 Rust 坚持的”共享不可写、可写不共享“的原则。我们看看 Rust 编译器的”道德底线“是如何被一步一步突破的吧。

1 Box 类型

我在《 Rust 的 Box指针》一文中详细讨论了 Box 的特点。看一个简单的例子:

fn main() {let x = String::from("Hello!");let y = Box::new(x);println!("{:?}", y);
}

其实这段代码与下面的代码几乎是等价的:

fn main() {let x = String::from("Hello!");let y = &x;println!("{:?}", y);
}

还有一段 Box 代码,展示了在设计链表结构时的用法:

#[derive (Debug)]
struct Node {data: i32,next: Option<Box<Node>>,
}
fn main() {let x &#61; Node {data: 123,next: None,};let y &#61; Box::new(x);println!("{:?}", y);
}
---------------------------------
>cargo run
Node { data: 123, next: None }

我尝试把 Box 改成 &&#xff0c;结果因为生命周期的问题&#xff0c;我整了老半天也没能通过编译。代码贴到下面&#xff0c;哪位大神能给是点一下&#xff1f;

#[derive (Debug)]
struct Node <&#39;a>{data: i32,next: Option<&&#39;a Node>,
}
fn main() {let x &#61; Node {data: 123,next: None,};let y &#61; Box::new(x);println!("{:?}", y);
}
---------------------------------
>cargo run--> src\main.rs:4:22|
4 | next: Option<&&#39;a Node>,| ^^^^ expected named lifetime parameter|
help: consider using the &#96;&#39;a&#96; lifetime

别管 & 能不能代替 Box&#xff0c;反正这件事告诉我&#xff0c;Box 帮助我们简化了好多工作&#xff0c;比直接用 & 更省事。

2 Rc 类型

看下面的代码&#xff1a;

use std::rc::Rc;
fn main() {let x &#61; Rc::new(123);let y &#61; x.clone();println!("{:?}, {:?}", x, y);
}
---------------------------------------------------
cargo run
123, 123

其实这个从逻辑上讲&#xff0c;也可以用 & 代替。一个变量的地址可以分配给多个变量&#xff0c;对不对&#xff1f;可是 rust 中的生命周期问题&#xff0c;够我们喝一壶的。所以&#xff0c;Rc 的存在价值就是可以避免生命周期检查&#xff0c;使得同一份数据可以在多个地方被引用。

3 Cell 类型

Cell 类型披着只读变量的外衣&#xff0c;允许程序修改变量内容。尽管 Rust 有一个原则——“共享不可写&#xff0c;可写不共享”&#xff0c;由于 Cell 表面上看是只读的&#xff0c;因此&#xff0c;Cell 类型的数据可以被多个地方引用&#xff0c;实现同一个数据可以被多个共享引用修改。因为 Cell 从语法上看是只读的&#xff0c;所以编译器不会报错。

Cell 可以用 get 方法返回数据。由于执行的 Copy 方法&#xff0c;因此要求数据必须实现 Copy 特性。

use std::cell::Cell;
fn main() {let x &#61; Cell::new(123);x.set(456);let y &#61; x.get();println!("{:?}, {:?}", x, y);
}
------------------------------------------------------
>cargo run
Cell { value: 456 }, 456

4 RefCell

RefCell 与 Cell 基本相同&#xff0c;区别在于 RefCell 读取内容时&#xff0c;返回的是引用&#xff0c;本质上是一个指针。这是因为 RefCell 要包装的数据没有实现 Copy 特性。代码示例如下&#xff1a;

use std::cell::{Ref, RefCell};
fn main() {let x &#61; RefCell::new("good".to_string());let a &#61; &x;let b &#61; &x;*a.borrow_mut() &#61; "nice".to_string();*b.borrow_mut() &#61; "best".to_string();let y: Ref<String> &#61; x.borrow();println!("x &#61; {:?}", x);println!("y &#61; {:?}", y);
}
---------------------------------------------------
>cargo run
x &#61; RefCell { value: "best" }
y &#61; "best"

5 总结


  • Box 等引用类型&#xff0c;简化了变量生命周期问题。
  • Rc 允许 clone() 方法产生变量的多个副本&#xff0c;但这些副本并未真正分配内存&#xff0c;而是共享了相同的数据。
  • Cell 在语法上看是只读的引用&#xff0c;而事实上是可以修改的。Cell 原则上只能引用实现了 Copy 特性的变量。
  • RefCell 与 Cell 类似&#xff0c;但是可以引用未实现 Copy 特性的变量。

推荐阅读
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
author-avatar
卢嘉怡i
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有