原文标题: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. SpringBoot第五集:整合监听器/过滤器和拦截器(2020最新最易懂)

    SpringBoot第五集:整合监听器/过滤器和拦截器(2020最新最易懂) 在实际开发过程中,经常会碰见一些比如系统启动初始化信息.统计在线人数.在线用户数.过滤敏/高词汇.访问权限控制(URL级别 ...

  2. ERROR: No matching distribution found for cv2

    ImportError: No module named cv2和No matching distribution found for cv2的问题 原因 这个是由于没有导入opencv库导致的 解决 ...

  3. 华为云FusionInsight MRS:助力企业构建“一企一湖,一城一湖”

    摘要:华为云FusionInsight MRS新一代的数据湖,让大数据越用越快.越用越易.越用越稳.越用越省!让数据价值近在眼前! 10月30日,以"携手共赢·数创未来"为主题的第 ...

  4. Union-Find算法应用

    上篇文章很多读者对于 Union-Find 算法的应用表示很感兴趣,这篇文章就拿几道 LeetCode 题目来讲讲这个算法的巧妙用法. 首先,复习一下,Union-Find 算法解决的是图的动态连通性 ...

  5. 解决SBT下载慢,dump project structure from sbt?

    一. 安装SBT,参考https://blog.csdn.net/zcf1002797280/article/details/49677881 二. 在~/.sbt下新建repositories添加如 ...

  6. 记录电子竞技游戏jesp中的传输过程公式

    1.json数据转换成字典 dict1 = json.load(load_f1) dict2 = json.load(load_f2) 2.将两个字典按key排好序,然后使用zip()函数将两个字典对 ...

  7. Java的浅拷贝与深拷贝

    Java的浅拷贝与深拷贝 Java中,所有的类都继承Object,Object中有clone方法,它被声明为了 protected ,所以我们但是如果要使用该方法就得重写且声明为public,必须在要 ...

  8. 三十二张图告诉你,Jenkins构建Spring Boot 有多简单~

    持续原创输出,点击上方蓝字关注我 目录 前言 如何安装Jenkins? 环境准备 开始安装Jenkins 初始化配置 访问首页 输入管理员密码 安装插件 创建管理员 实例配置 配置完成 构建Sprin ...

  9. C# 全局唯一标识符 (GUID)

    一 C#  全局唯一标识符 (GUID) Represents a globally unique identifier (GUID). To browse the .NET Framework so ...

  10. 关于BigDecimal转String的准确性问题

    case 1: String str=new BigDecimal(123.9).toString() 输出str:123.90000000000000568434188608080148696899 ...