Rust借用机制的理解分析
Rust初学者大多会遇到这样的问题:
- 为什么同一资源不可被同时可变借用和不可变借用?
- 为什么Rc一定只能是只读的,一定要配合std::cell系列(Cell,RefCell,UnsafeCell)才能提供可变性?为什么不设计一个可变的Rc?
- 为什么Mutex/RwLock一般都会配合Arc使用?
 ……
这一类借用规则的问题,实际上都可以通过另一种思路来很好地解答,当然这也是很多大佬一定程度上认可的理解方式:
Rust中的借用,分为不可变借用共享借用,和可变借用独占借用
无论在教程中,还是语法中,我们都用可变性来区分二种借用,最开始,最直观的理解:
- 因为是可变借用,多方借用会导致冲突,因此可变借用是独占的。
- 因为是不可变借用,多方借用只读数据不会导致冲突,因此不可变借用是可共享的。
但是我们可以试着换一个方向去思考,用独占性去区分两种借用,很多问题便可以轻易理解:
- 因为是独占借用,对资源的任何形式的访问都只能有一方可以被允许,所以对它的改变是安全无害的。
- 因为是共享借用,对资源的访问可以有多方共同进行,所以对其中任何一方而言,来自其他方的改变是不可控的,所以对它的改变并不是安全无害的,因此它只允许只读访问。
这样的思考方式从“可变性==>独占性”换成了“独占性==>可变性”,首先就直观地解释了“同一资源不可同时被可变借用和不可变借用”的问题,因为“独占借用”从字面上就不可能跟其他任何形式的借用共存。
再说到Rc/Arc。Rc是通过引用计数来提供安全的共享访问的只能指针,在C++中本就叫做"shared_ptr",从逻辑上就是提供共享访问的工具,不应被任何一方独占,因此也理应只提供共享借用。而Arc就是线程安全版的Rc。
无论是std::cell系列还是Mutex/RwLock,它们的目的都一致:为共享资源提供安全的可变访问。由于既需要共享,也需要可变,因此无法用“独占=可变,共享=不可变”的类型模型去编译期检查访问的安全性,只能在运行时通过实际的行为去动态检查,保证“同一时间,一个资源只可以被一方可变访问,或被多方不可变访问”的原则。只是它们的行为略有不同:
- UnsafeCell仅仅是一层包装壳,在对本身的访问不需要所有权或独占借用,仅提供共享借用的前提下,提供对内含资源的独占引用访问,因为没有任何策略保证访问的安全,因此对其的操作是unsafe的。
- Cell屏蔽掉了UnsafeCell的引用访问,只提供存取访问。由于在单线程下,调用函数即完全交出控制权,存取都可被视为原子操作,而资源本身也从一个静态的资源变成了一个需要操作去存取的读写对象,因此自然也保证了安全访问的原则。
- RefCell在UnsafeCell的基础上,以性能为代价,加入了运行时检查机制以提供安全的引用访问。由于引用可以在调用结束后持续地被持有,因此需要guard(通过自身的RAII来控制目标资源的占用与解除占用的结构)来运行时监控当前资源被访问的形式和数量,在打破安全访问的原则时及时抛出panic来避免ub。
- RwLock是线程安全版的RefCell,通过调用系统底层的线程锁来实现线程安全,在打破安全访问原则时阻塞后续的访问而不是panic,以等待目前的占用解除。
- Mutex是只读访问互斥版的RwLock,即使不存在可写访问,仍然会在已有只读访问占用时阻塞后续的只读访问。
不难看出,很多情况下,Arc<RwLock>的组合实际上跟Rc<RefCell>的逻辑是一致的:在需要共享的可变资源时,先用Rc/Arc控制资源的生命周期,再用RefCell/RwLock来控制资源的访问安全,区别在于是否为跨线程访问提供支持。
综上所述,以个人经验来讲,在习惯上以独占借用/共享借用的视角来分析,而不是可变借用/不可变借用,更有助于理解借用规则的实质,希望以此可以给初接触Rust的同行一些启发。
Rust借用机制的理解分析的更多相关文章
- Springboot学习04-默认错误页面加载机制源码分析
		Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ... 
- Android事件分发机制源码分析
		Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ... 
- Redis数据持久化机制AOF原理分析一---转
		http://blog.csdn.net/acceptedxukai/article/details/18136903 http://blog.csdn.net/acceptedxukai/artic ... 
- 浅谈 Attention 机制的理解
		什么是注意力机制? 注意力机制模仿了生物观察行为的内部过程,即一种将内部经验和外部感觉对齐从而增加部分区域的观察精细度的机制.例如人的视觉在处理一张图片时,会通过快速扫描全局图像,获得需要重点关注的目 ... 
- [转]as3事件流机制彻底理解
		题记: 看过网上一些as3事件流的教程,觉得大多都讲得不甚清楚,让人不能直观的理解事件流.而这篇教程以将事件流过程比喻成捕鱼过程,形象简单. 在此基础上对于as3事件流总算有了全面的理解.事件流机制说 ... 
- Linux内核OOM机制的详细分析(转)
		Linux 内核 有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了 防止内存耗尽而内核会把该进程杀掉.典 ... 
- 我对asp.net运行机制的理解
		有一本书叫<asp.net 本质论>,作者名叫冠军.我看了几次,都没有坚持看下来.这次连续看完了前三章,然后参考网上的资料,总结下我对.net运行机制的理解. 先上两张图: 看着这两张图, ... 
- JDK动态代理深入理解分析并手写简易JDK动态代理(下)
		原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ... 
- JDK动态代理深入理解分析并手写简易JDK动态代理(上)
		原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ... 
随机推荐
- Vue iview Tree组件实现文件目录-基础实现
			注册页面路由 router/router.js { path: 'folder_tree', name: 'folderTree', component: () => import('@/vie ... 
- java对象相等
			https://www.dutycode.com/post-140.html 简单来首,Object方法里的equals也是直接判断两个引用是否指向同一个地址,即引用同一个对象 public bool ... 
- 使用Golang的singleflight防止缓存击穿
			背景 在使用缓存时,容易发生缓存击穿. 缓存击穿:一个存在的key,在缓存过期的瞬间,同时有大量的请求过来,造成所有请求都去读dB,这些请求都会击穿到DB,造成瞬时DB请求量大.压力骤增. singl ... 
- volatile域浅析
			内存模型的相关概念 计算机中执行程序时,每条指令都是在CPU中执行,执行指令的过程必然会涉及到数据的读取和写入.而程序运行时的数据是存放在主存(物理内存)中,由于CPU的读写速度远远高于内存的速度,如 ... 
- 使用Scrcpy实现电脑控制安卓手机
			很多时候我们想要在电脑上使用一些手机软件,使用模拟器当然是一种选择,但是这些模拟器要不然不免费,要不然广告多不放心.Scrcpy是一个开源免费的软件,通过abd命令实现了安卓手机投屏和控制功能,并且支 ... 
- SpringBoot一统江湖
			一 SpringBoot简介 SpringBoot是Spring框架的一个新子项目 用于创建Spring4.0项目 它的开发始于2013年 2014年4月发布1.0.0版本 它可以自动配置Spring ... 
- 使用implicitly demo
			泛型: Context Bounds // //定义一个隐式值, 这个值不能少, 要不找不到比较的对象 implicit val personCompartor = new Ordering[Per ... 
- python3  进行接口测试
			最近有研究接口测试,然后查了查资料,发现有两种方法,一种是使用urllib库,一种是使用requests库.而在这里,我使用的是requests库,为什么要用这个呢? 从官方文档看出,python的标 ... 
- 给子元素设置margin-top无效果的一种解决方法
			在写一个登陆界面的时候,设置登录按钮的margin-top时出了问题 先是这么写的 <div style="margin-top:30px"> <a style= ... 
- c++中sprintf和sprintf_s的区别
			参考:https://blog.csdn.net/qq_37221466/article/details/81140901 sprintf_s是sprintf的安全版本,指定缓冲区长度来避免sprin ... 
