原文标题:Understanding Partial Moves in Rust


原文链接:https://whileydave.com/2020/11/30/understanding-partial-moves-in-rust/


公众号: Rust 碎碎念


翻译 by: Praying

最近,我一直在研究Rust,虽然从很多方面来看它都是一门十分优秀的语言,但我也发现了很多不易察觉的复杂性。其中一个例子就是,不太引人注意的局部移动(partial move) 。因此,我在想,为什么不写一篇文章来介绍它呢?

所有权(简洁版)

我不准备在这里介绍Rust中所有权和借用的全部细节。不过,这里我们仍然需要一些背景知识使得局部移动(partial move)能够讲得通。下面通过是一个box和一个箭头头来表示Rust中的所有权!

在一个没有所有权的世界里(想想Java、C/C++),我们可以通过别名(aliasing)毫无限制地引用数据。我们可以让两个引用指向相同的数据,数据之间互相引用等等。

在所有权的世界里(即Rust),一个引用可以拥有它所指向的数据。在这种情况下,不允许再有对该数据的持有所有权的其他引用(owning references)。例如,如果两个引用指向相同的数据(即上图中中间的情况),只有一个引用可以是所有者。

这种对关联所有权的引用的限制影响了我们写程序的方式。假定我们试图从变量p拷贝一份持有所有权的引用到变量q:

这就行不通了,因为它破坏了所有权的不变性 。如果允许这种情况,我们将会对同一份数据持有两个带有所有权的引用,而这是不被允许的。所以,我们该怎么办呢?我们可以移动(move)它


在上图中,变量p的值经过移动(move)操作后已经作废,在对p赋予新的值之前,我们不能再使用它了。当然,这也对我们使用Rust编写程序产生了相当大的影响。但是,我不准备在这里讨论这个问题。

局部移动(Partial Moves)

目前为止,我已经看到了一次性移动(move)整个变量(例如,上面中从p移动到q)。此外,我们还可以执行一个局部移动(partial move),在局部移动(partial move)中,可以仅移动(move)给定变量的一部分内容。假定现在我们的变量p是一个pair,其中每个元素包含一个持有所有权的引用。然后,我们可以把p中的第二个元素移动到另一个变量q中,如下图所示:

这个例子的有趣之处在于,不同于之前的情况,尽管变量p的一部分内容已经失效,但它仍然可以以一种受限的方式被使用。具体来讲,我们可以使用p.0但是不能使用p.1。此外,Rust阻止我们对变量p进行整个的拷贝(copy)或移动(move)(尽管在我看来,这并没有必要)。上面的示例转为代码,如下:

fn main() { 
    let mut x = 123;
    let mut y = 456;
    let mut p = (&mut x,&mut y);
    let mut q = p.1;
    ...
}

目前为止,一切都好。但是,当对...进行替换, 比如替换为let mut z = p;时,我们会得到下面的错误信息:

error[E0382]: use of partially moved value: `p`
 --> src/main.rs:6:17
  |
5 | let mut q = p.1;
  |             --- value partially moved here
6 | let mut z = p;
  |             ^ value used here after partial move

只是简单地告诉我们,我们不能使用一个由于之前的移动(move)操作而已经失效的值。个人而言,我不太理解为什么Rust阻止这种移动(move)操作,因为能够很容易地推导出z只是被部分定义(译注:即另一部分无效),就像它对p所做的那样。想必是,尽管可以推导,但是通过某个引用对p赋值必然会导致某些问题吧。

总结

Rust是一门相当酷的语言,但是仍然有很多微妙的特性。希望这篇文章可以帮助解答其中的一个困惑。

【译】理解Rust中的局部移动的更多相关文章

  1. 【译】理解Rust中的闭包

    原文标题:Understanding Closures in Rust 原文链接:https://medium.com/swlh/understanding-closures-in-rust-21f2 ...

  2. 【译】理解Rust中的Futures (一)

    原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...

  3. 【译】理解Rust中的Futures(二)

    原文标题:Understanding Futures in Rust -- Part 2 原文链接:https://www.viget.com/articles/understanding-futur ...

  4. 【译】深入理解Rust中的生命周期

    原文标题:Understanding Rust Lifetimes 原文链接:https://medium.com/nearprotocol/understanding-rust-lifetimes- ...

  5. 【译】Rust中的array、vector和slice

    原文链接:https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/ 原文标题:Arrays, vectors and slices in ...

  6. [NodeJs系列][译]理解NodeJs中的Event Loop、Timers以及process.nextTick()

    译者注: 为什么要翻译?其实在翻译这篇文章前,笔者有Google了一下中文翻译,看的不是很明白,所以才有自己翻译的打算,当然能力有限,文中或有错漏,欢迎指正. 文末会有几个小问题,大家不妨一起思考一下 ...

  7. 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?

    我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...

  8. [译]线程生命周期-理解Java中的线程状态

    线程生命周期-理解Java中的线程状态 在多线程编程环境下,理解线程生命周期和线程状态非常重要. 在上一篇教程中,我们已经学习了如何创建java线程:实现Runnable接口或者成为Thread的子类 ...

  9. 如何理解javaSript中函数的参数是按值传递

    本文是我基于红宝书<Javascript高级程序设计>中的第四章,4.1.3传递参数小节P70,进一步理解javaSript中函数的参数,当传递的参数是对象时的传递方式. (结合资料的个人 ...

随机推荐

  1. python数据类型互相转换

    类型转换 关注公众号"轻松学编程"了解更多. 主要针对几种存储工具:list.tuple.dict.set 特殊之处:dict是用来存储键值对的. 1.list 转换为set l1 ...

  2. UML类图关系表示

    UML 之 C++类图关系全面剖析 分类: 软件设计与架构2008-10-16 08:52 5165人阅读 评论(3) 收藏 举报 umlc++borderclasscblog UML的类图关系分为: ...

  3. XJOI 7191 Genius ACM

    二分+倍增 题目 题目中的最大校验值应由数组排序后,取出最大值和最小值,次大值和次小值--进行做差平方取和 所以在加入一个新的数时,校验值是不会下降的 那么可以发现,校验值是单调递增的,所以可以用二分 ...

  4. Lte Design Documentation之RRC

    RRC 特点 RRC模型在模拟器中提供以下功能 生成(在eNB中)和解释(在UE中)信息块(尤其是MIB和SIB1, SIB2) 初始化小区选择 RRC连接建立过程 RRC重新配置程序, 支持以下方式 ...

  5. Es6-Promise初识

    Promise 含义: Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Pro ...

  6. ros启动节点Error: package 'chapter2_tutorials' not found问题

    在学习ROS时,实现节点之间的通信时,参考ROS机器人高效编程,每次启动节点的时候 $ rosrun chapter2_tutorials example1_a 都会提示 Error: package ...

  7. rabbitmq-参考

    rabbitMQ http://lynnkong.iteye.com/blog/1699684 http://jzhihui.iteye.com/category/195005

  8. epoll源码解析翻译------说使用了mmap的都是骗子

    本文地址 //https://www.cnblogs.com/l2017/p/10830391.html //https://blog.csdn.net/li_haoren select poll e ...

  9. git bash: error: RPC failed; result = 18, HTP code = 200B

    git config --global http.postBuffer 2428800 如果还是失败,说明buffer不够大,继续增加buff git config --global http.pos ...

  10. ceph的jewel新支持的rbd-nbd

    jewel版本新增加了一个驱动NBD,允许librbd实现一个内核级别的rbd NBD相比较于kernel rbd: rbd-ko是根据内核主线走的,升级kernel rbd需要升级到相应的内核,改动 ...