Rust- 智能指针
Smart pointers
A smart pointer is a data structure that not only acts like a pointer but provides additional functionality. This “smartness” comes from the fact that smart pointers encapsulate additional logical or semantic rules, which are automatically applied to simplify memory or resource management tasks.
While different programming languages implement smart pointers in various ways, they all share a common goal: to manage the life cycle of the resources they point to.
Here are some key features of smart pointers:
-
Ownership: Smart pointers keep track of the memory they point to, and can automatically reclaim (or “free”) that memory when it’s no longer needed. This can greatly simplify memory management, as the programmer doesn’t need to manually release memory, reducing the risk of memory leaks.
-
Reference Counting: Some smart pointers, like the
Rc<T>
in Rust orshared_ptr
in C++, keep a count of the number of references (i.e., pointers) to an object. This object is only deallocated when there are no more references to it. -
Dereferencing: Like regular pointers, smart pointers implement the dereferencing operation, allowing access to the data they point to.
-
Polymorphism: In object-oriented languages, smart pointers can be used to enable polymorphism when pointing to base and derived class objects.
-
Thread Safety: Some smart pointers, like
Arc<T>
in Rust orstd::atomic_shared_ptr
in C++20, are thread-safe, meaning they can be safely used in concurrent programming.
In Rust, smart pointers are essential components due to the language’s focus on safety and zero-cost abstractions. Box<T>
, Rc<T>
, and RefCell<T>
are some of the commonly used smart pointers in Rust.
-
Box<T>
: This is the simplest kind of smart pointer. It allows you to put data on the heap rather than the stack.Box<T>
is often used in Rust in two scenarios: when you have a type of known size but need to store a value of a type that might have an unknown size at compile time, or when you have a large data item and want to transfer ownership to a function without copying the data to prevent stack overflow. -
Rc<T>
: “Rc” stands for reference counting. TheRc<T>
smart pointer allows your program to have multiple read-only references to the same data item on the heap. It keeps track of the number of references to the data on the heap, and once the reference count goes to zero, meaning there are no more references to the data, it cleans up the data. -
RefCell<T>
: Rust performs borrow checking at compile time which ensures that references to data obey the rules of either one write or multiple reads. However, sometimes you may need to do such checking at runtime.RefCell<T>
provides this functionality. This means that while you can borrow mutable references at runtime, your program will panic if you violate the rules of one write or multiple reads.
These are some of the basic smart pointers in Rust. There are several other smart pointers, like Arc<T>
, Mutex<T>
, etc., which are all designed to deal with ownership and concurrency issues in Rust.
It’s worth noting that while these types are called “smart pointers”, they’re not limited to mimicking pointer-like behavior. They’re actually more general constructs often used to add structure to a value, such as tracking reference counts, thread-safe access, and more.
Box< T >
Box<T>
is a very important smart pointer in Rust. It allows you to store data on the heap rather than the stack. This is mainly used in Rust for the following two scenarios:
-
Moving data to the heap: By default, Rust stores data on the stack. However, stack space is limited and the data on the stack is immediately removed when it goes out of scope. If you need to store a large amount of data in memory or need to pass data between scopes without losing ownership, you can use
Box<T>
to move the data to the heap. -
Storing dynamically sized types: In Rust, the size of all types must be known at compile time. However, there might be cases where you want to store a type whose size is not known at compile time.
Box<T>
can be used in this case, as the size ofBox<T>
itself is known regardless of the size of the data on the heap it points to.
When using Box<T>
, Rust will automatically clean up the data on the heap when the Box<T>
goes out of scope, meaning you do not need to manually manage memory.
Here is a simple example of Box<T>
:
fn main() {let b = Box::new(5); // b is a pointer to a box in the heapprintln!("b = {}", b);
}
In this example, the integer 5 is stored on the heap, rather than on the stack. The variable b
is a pointer to the value stored on the heap. When b
goes out of scope, Rust’s automatic memory management system cleans up the data on the heap, so you do not need to manually free the memory.
use std::ops::Deref;
fn main() {/*如果一个结构体实现了deref和drop的Trait,那他们就不是普通结构体了。Rust提供了堆上存储数据的能力并把这个能力封装到了Box中。把栈上的数据搬到堆上的能力,就叫做装箱。Box可以把数据存储到堆上,而不是栈上,box 装箱,栈还是包含指向堆上数据的指针。*/let a = 6;let b = Box::new(a);println!("b = {}", b); // b = 6let price1 = 158;let price2 = Box::new(price1);println!("{}", 158 == price1); // trueprintln!("{}", 158 == *price2); // truelet x = 666;let y = CustomBox::new(x);println!("666 == x is {}", 666 == x); // 666 == x is trueprintln!("666 == *y is {}", 666 == *y); // 666 == *y is trueprintln!("x == *y is {}", x == *y); // x == *y is true
}struct CustomBox<T> {value: T
}impl <T> CustomBox<T> {fn new(v: T) -> CustomBox<T> {CustomBox { value: v }}
}impl <T> Deref for CustomBox<T> {type Target = T;fn deref(&self) -> &T {&self.value}
}impl <T> Drop for CustomBox<T> {fn drop(&mut self) {println!("drop CustomBox 对象!")}
}
Rc < T >
Rc<T>
stands for ‘Reference Counting’. It’s a smart pointer that allows you to have multiple owners of the same data. When each owner goes out of scope, the reference count is decreased. When the count reaches zero, the data is cleaned up.
Here’s a simple example:
use std::rc::Rc;fn main() {let data = Rc::new("Hello, World!"); // data now has a reference count of 1{let _clone = Rc::clone(&data); // data now has a reference count of 2println!("Inside the scope, data is: {}", *_clone);} // _clone goes out of scope and data's reference count decreases to 1println!("Outside the scope, data is: {}", *data);
} // data goes out of scope and its reference count decreases to 0, the data is cleaned up
RefCell < T >
RefCell<T>
provides ‘interior mutability’, a design pattern in Rust that allows you to mutate data even when there are immutable references to that data. It enforces the borrowing rules at runtime instead of compile time.
Here’s a simple example:
use std::cell::RefCell;fn main() {let data = RefCell::new(5);{let mut mutable_reference = data.borrow_mut();*mutable_reference += 1;println!("Inside the scope, data is: {}", *mutable_reference);} // mutable_reference goes out of scope, the lock is releasedprintln!("Outside the scope, data is: {}", *data.borrow());
}
In this example, you can see that we borrowed a mutable reference to the data inside RefCell
using borrow_mut
, modified it, and then the lock was automatically released when the mutable reference went out of scope. This demonstrates the dynamic checking that RefCell<T>
provides.
Note1: The borrow_mut()
function is a method of RefCell<T>
in Rust. This function is used to gain mutable access to the underlying value that the RefCell
wraps around.
The RefCell
struct in Rust enforces the borrow rules at runtime, allowing you to have multiple immutable references or one mutable reference at any point in time. If you attempt to violate these rules, your program will panic at runtime.
When you call borrow_mut()
on a RefCell
, you get a RefMut
smart pointer that allows mutable access to the underlying data. Once this RefMut
is dropped (which happens automatically when it goes out of scope), others can then borrow the RefCell
again.
Here’s an example:
use std::cell::RefCell;fn main() {let data = RefCell::new(5);{let mut mutable_reference = data.borrow_mut();*mutable_reference += 1;println!("Inside the scope, data is: {}", *mutable_reference);} // mutable_reference goes out of scope, the lock is releasedprintln!("Outside the scope, data is: {}", *data.borrow());
}
In this example, mutable_reference
is a mutable reference to the integer wrapped in data
, which is a RefCell
. We increment the integer by 1, and after mutable_reference
goes out of scope, we can borrow data
again.
Note2: The borrow()
function is a method of RefCell<T>
in Rust. This function is used to gain immutable access to the underlying value that the RefCell
wraps around.
Similar to borrow_mut()
, it provides a way to access the data inside the RefCell
. The difference is that borrow()
gives you an immutable reference (Ref<T>
), while borrow_mut()
gives you a mutable reference (RefMut<T>
).
The RefCell
checks at runtime to make sure the borrowing rules are not violated, which are:
- You may have either one mutable reference or any number of immutable references at the same time, but not both.
- References must always be valid.
If you try to call borrow()
when the value is already mutably borrowed (through borrow_mut()
), or try to call borrow_mut()
when the value is immutably borrowed (through borrow()
), your program will panic at runtime.
Here’s how you might use borrow()
:
use std::cell::RefCell;fn main() {let data = RefCell::new(5);{let mutable_reference = data.borrow_mut();*mutable_reference += 1;} // mutable_reference goes out of scope, the lock is releasedlet immutable_reference = data.borrow();println!("Data is: {}", *immutable_reference);
}
In this example, we first use borrow_mut()
to mutate the value inside data
, then we use borrow()
to get an immutable reference to the data.
相关文章:
Rust- 智能指针
Smart pointers A smart pointer is a data structure that not only acts like a pointer but provides additional functionality. This “smartness” comes from the fact that smart pointers encapsulate additional logical or semantic rules, which are automaticall…...

什么是微服务
微服务的架构特征: 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责自治:团队独立、技术独立、数据独立,独立部署和交付面向服务:服务提供统一标准的接口࿰…...

无人机电力巡检方案在电网安全与维护中的应用
目前,无人机技术已经在各行各业都有广泛的应用,其中之一就是在电力巡检中的应用。无人机电力巡检方案以其高效、安全、精准的特点,为电网安全与维护带来了重大突破和进步。 一、无人机电力巡检方案是高效巡检的利器 传统的电力巡检方式需要人…...

网络工程师 快速入门
需要掌握 以下技术 1.网络 基础 知识 TCP/IP 、OSI 7层协议、IP地址、ARP地址解析协议、ICMP(英特网控制报文协议,ping)等 入门面试常问问题。 2.路由 路由匹配 三原则、静态路由、OSPF路由协议。 2.交换 如何放数据? VLAN TRU…...

Linux系统vim查看文件中文乱码
Linux系统查看文件-cat中文正常显示 vim中文乱码 1、背景2、环境3、目的4、原因5、操作步骤5.1、修改vim编码配置 6、验证 1、背景 服务器部署业务过程中查看文件内容,使用cat 命令查看中文正常显示,使用vim命令查看显示中文乱码 cat 查看 vim 查看 …...
BladeX框架开源-工作-笔记-Docker部署-Jenkins配置
BladeX框架开源-工作-笔记-Docker部署-Jenkins配置 文章目录 BladeX框架开源-工作-笔记-Docker部署-Jenkins配置第一章-概要-BladeX框架简介与git地址第二章-BladeX框架前后端项目Docker部署与DockerFile配置文件2.1-开始部署阶段,默认服务器上面已有Nacos服务2.2-采…...

Modbus tcp转ETHERCAT网关modbus tcp/ip协议
捷米JM-ECT-TCP网关能够连接到Modbus tcp总线和ETHERCAT总线中,实现两种不同协议设备之间的通讯。这个网关能够大大提高工业生产的效率和生产效益,让生产变得更加智能化。捷米JM-ECT-TCP 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主要功能是…...

RK356x Android11更换默认的Launcher
1、 开发环境 ubuntu版本:18.04 开发平台:RK356x Android版本:android11 2、目的 android11 系统自带了一个启动器Launcher3,在android源码路径下的packages/apps/Launcher3下,现需要将我们自己开发的Launcher放到a…...
Python 操作 MySQL 数据库
Python 操作 MySQL 数据库 Python 标准数据库接口为 Python DB-API,Python DB-API为开发人员提供了数据库应用编程接口。 Python 数据库接口支持非常多的数据库,你可以选择适合你项目的数据库: GadFlymSQLMySQLPostgreSQLMicrosoft SQL Se…...

脑电信号处理与特征提取——6.运用机器学习技术和脑电进行大脑解码(涂毅恒)
目录 六、运用机器学习技术和脑电进行大脑解码 6.1 前言 6.2 基于脑电数据的机器学习基础分析 6.3 基于脑电数据的机器学习进阶分析 6.4 代码解读 六、运用机器学习技术和脑电进行大脑解码 6.1 前言 6.2 基于脑电数据的机器学习基础分析 6.3 基于脑电数据的机器学习进阶分…...

腾讯云COS+PicGO+截图工具+Obsidian+Typora+蚁小二:打造丝滑稳定的Markdown写作和分发环境
背景 很久很久以前,我写过一篇《有道云笔记EverythingTyporaGitHub图床PicGojsDelivr加速截图工具——创造丝滑免费的Markdown写作环境》(https://blog.csdn.net/qq_43721542/article/details/9685957),当时的目的是打造一个云同…...

LeetCode--HOT100题(18)
目录 题目描述:73. 矩阵置零(中等)题目接口解题思路1代码解题思路2代码 PS: 题目描述:73. 矩阵置零(中等) 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都…...
ES6的语法兼容IE浏览器
案例1 zdsxData.zdsxData.forEach(el>{let str <tr> <td><a href${el.url} target"_blank"><font color"#79EEFF">${el.sxms}</font></a></td> <td>${el.gjjd}</td> <td>${el.zrr}<…...
【opencv学习】鼠标回调函数、鼠标控制画矩形
#include <iostream> #include <opencv2/opencv.hpp> using namespace cv; #define WinDow "程序窗口"void MouseHandle(int event, int x, int y, int flags, void* param);//鼠标回调函数 void Drawrectangle(cv::Mat& img, cv::Rect box);//矩形绘…...
Typescript面试题
文章目录 了解过TS吗?使用ts写一个对象属性约束说一下typescript中的泛型如何在TS中对函数的返回值进行类型约束ts和js相比有什么区别 了解过TS吗? ts是一种基于静态类型检查的强类型语言 let num:number20 console.log(num) console.log("str&qu…...

GB28181智能安全帽方案探究及技术实现
什么是智能安全帽? 智能安全帽是一种集成先进科技的安全帽,可基于GB28181规范,适用于铁路巡检、电力、石油化工等高风险行业的作业人员,以及消防、救援等紧急情况下的安全防护。 智能安全帽通常具有以下功能: 实时…...

【css】解决元素浮动溢出问题
如果一个元素比包含它的元素高,并且它是浮动的,它将“溢出”到其容器之外:然后可以向包含元素添加 overflow: auto;,来解决此问题: 代码: <!DOCTYPE html> <html> <head> <style>…...

SOC FPGA之流水灯设计
一、DS-5简介 Altera Soc EDS开发套件的核心是Altera版ARM Development Studio 5(DS-5)工具包,为SoC器件提供了完整的嵌入式开发环境、FPGA自适应调试和对Altera工具的兼容。 1.1 DS-5 eclipse破解 首先下载破解器 然后进入cmd运行,进入到破解器所在文…...

无涯教程-Lua - Iterators(迭代器)
迭代器是一种构造,使您可以遍历所谓的集合或集合的元素。在Lua中,这些集合通常引用表,这些表用于创建各种数据结构(如数组)。 通用迭代器 通用的 for 迭代器提供集合中每个元素的键值对。下面给出一个简单的示例。 array{"Lua",…...

HTML+CSS+JavaScript:实现B站评论发布效果
一、需求 1、用户输入内容,输入框左下角实时显示输入字数 2、为避免用户输入时在内容左右两端误按多余的空格,在发送评论时,检测用户输入的内容左右两端是否带有空格,若有空格,发布时自动取消左右两端的空格 3、若用…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...

【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...