最近,在使用Rust时遇到了Reborrow的概念,记录下来以备以后参考。

1. 起因

起因准备对数据进行Min-Max标准化处理,也就是将一系列数据映射到一个新的范围。

首先,需要遍历数据,找出其中的最大值最小值,然后通过公式改变原始数据集的值。

Min-Max公式:标准化后的值 = (原始值 - 最小值) / (最大值 - 最小值)

简化后的代码如下:

fn main() {
let mut values = vec![10.5, 22.3, 103.5, 45.75];
let v = &mut values;
println!("原始数据: {:#?}", v); let mut max = f64::MIN;
let mut min = f64::MAX; for n in v {
if *n > max {
max = *n;
}
if *n < min {
min = *n;
}
} println!("max is {}", max);
println!("min is {}", min); println!("开始Min-Max标准化处理...");
for n in v {
*n = (*n - min) / (max - min);
} println!("处理后数据: {:#?}", values);
}

运行时有如下错误:

error[E0382]: use of moved value: `v`
--> src/main.rs:22:14
|
3 | let v = &mut values;
| - move occurs because `v` has type `&mut Vec<f64>`, which does not implement the `Copy` trai
t
...
9 | for n in v {
| - `v` moved due to this implicit call to `.into_iter()`
...
22 | for n in v {
| ^ value used here after move
|

大概是第9行遍历v的找出最大值和最小值时候,可变借用v的使用权已经转移了,

所以在第22行再次遍历v去修改值的时候,出现错误。

这里,因为Vector没有实现Copy Trait,所以它的可变借用在第一次遍历时,由于隐式的调用了.into_iter(),所有权发生了转移。

如果想多次遍历Vector,可以使用它的不可变借用,比如定义let v = &values;

那么,就可以多次遍历v,因为不可变借用都实现了Copy Trait

但是,我第二次遍历v的时候,还需要修改其中的值,所以必须定义为可变借用let v = &mut values;

通过查询资料,发现Reborrow的机制可以实现上面的需求。

2. Reborrow概念

借用(Borrow)是Rust中的一个重要概念,它是允许代码访问某个值而不获取其所有权的一种机制。

Reborrow则是指在一个已存在的借用基础上创建一个新的借用,

这个新的借用可以是不可变的,也可以是可变的(前提是原始借用是可变的,并且没有其他借用存在)。

总的来说,Reborrow通过在已存在的借用上创建新的借用,从而扩展引用的生命周期并在更广泛的作用域内安全地访问值。

3. 解决方法

下面通过实践来检验对Reborrow概念的理解。

回到第一节中遇到的问题,解决方式就是在第一次遍历v时(第9行),不要把所有权转移出去,

这样,第二次遍历v第22行)的时候,就不会报出"value used here after move"的错误。

根据Reborrow的机制,我们在第9行可以Reborrow可变借用v,这样转移出去的是被再次借用的v,而不是v本身。

改变方法很简单,第9行改为for n in &*v {即可,也就是先还原v(*v),然后Reborrow(&*v)。

修改后再次运行代码:

$  cargo run

原始数据: [
10.5,
22.3,
103.5,
45.75,
]
max is 103.5
min is 10.5
开始Min-Max标准化处理...
处理后数据: [
0.0,
0.12688172043010754,
1.0,
0.3790322580645161,
]

values中的数据可以正常转换了。

注意,这里是将vReborrow成一个不可变借用&*v,因为我第一次遍历时不需要改变v

如果想vReborrow成一个可变借用,可以写成:&mut *v

Rust的Reborrow机制的更多相关文章

  1. Rust语言:安全地并发

    http://www.csdn.net/article/2014-02-26/2818556-Rust http://www.zhihu.com/question/20032903 Rust是近两年M ...

  2. 半个月使用rust语言的体验

    从第一次下载rust语言的编译器到今天刚好第14天. 简单说一下对这个语言的感觉吧. 一.性能 把以前用java写的一个中文地址切分的算法,用rust重新实现了一下(https://github.co ...

  3. Rust到底值不值得学--Rust对比、特色和理念

    前言 其实我一直弄不明白一点,那就是计算机技术的发展,是让这个世界变得简单了,还是变得更复杂了. 当然这只是一个玩笑,可别把这个问题当真. 然而对于IT从业者来说,这可不是一个玩笑.几乎每一次的技术发 ...

  4. Rust入坑指南:万物初始

    有没有同学记得我们一起挖了多少个坑?嗯-其实我自己也不记得了,今天我们再来挖一个特殊的坑,这个坑可以说是挖到根源了--元编程. 元编程是编程领域的一个重要概念,它允许程序将代码作为数据,在运行时对代码 ...

  5. the rust book 的简单入门笔记

    rust learning day 1 (2021/05/27) 学了常量,变量,数据类型,控制流,所有权 char 的宽度是4字节,一个 unicode 的宽度 控制流条件都不要括号 rust 中的 ...

  6. Rust所有权及引用

    Rust 所有权和借用 Rust之所以可以成为万众瞩目的语言, 就是因为其内存安全性. 在以往内存安全几乎全都是通过GC的方式实现, 但是GC会引来性能.CPU以及Stop The World等问题, ...

  7. 最强肉坦:RUST多线程

    Rust最近非常火,作为coder要早学早享受.本篇作为该博客第一篇学习Rust语言的文章,将通过一个在其他语言都比较常见的例子作为线索,引出Rust的一些重要理念或者说特性.这些特性都是令人心驰神往 ...

  8. Rust实战系列-基本语法

    本文是<Rust in action>学习总结系列的第二部分,更多内容请看已发布文章: 一.Rust实战系列-Rust介绍 " 主要介绍 Rust 的语法.基本类型和数据结构,通 ...

  9. 学习Rust第一天 Rust语言特点

    学习Rust之前,我觉得应该首先了解Rust语言的设计目的是什么?为什么会诞生这门语言?这门语言和其他的语言有什么不同. Rust语言的设计特点 高性能:rust拥有和C++相近的性能表现,所以在嵌入 ...

  10. Rust借用机制的理解分析

    Rust初学者大多会遇到这样的问题: 为什么同一资源不可被同时可变借用和不可变借用? 为什么Rc一定只能是只读的,一定要配合std::cell系列(Cell,RefCell,UnsafeCell)才能 ...

随机推荐

  1. 字符串系列目录&&说明

    字符串准备写成一个系列. 目录 \(\text{KMP笔记}\) \(\text{Manacher笔记}\) [] [] [] 格式与说明 下面的说明和格式将被应用于整个系列. 说明 所有字符串的下标 ...

  2. AC自动机 基础篇

    AC 自动机1 前置知识:\(KMP\),字典树. \(AC\) 自动机,不是用来自动 \(AC\) 题目的,而是用来处理字符串问题的(虽然确实可以帮助你 \(AC\)). 这里总结了 \(AC\) ...

  3. 国内IT行业67家外包公司,有多少程序员在里面待过?

    之前写过一篇关于外包公司的文章, <什么是软件外包公司?要不要去外包公司?> 很多粉丝看了后,感觉都在说自己, 存在即合理, 外包大幅度降(可)低(以)了(压)用(榨)人(更)成(多)本( ...

  4. love music

    https://music.163.com/outchain/player?type=2&id=215239

  5. Chrome扩展插件的开发--获取网页Cookies

    Chrome扩展插件的开发--获取网页Cookies Chrome浏览器在浏览器类应用软件中一直居于榜首,很多人选择Chrome浏览器不仅仅是因为它的稳定,还有它丰富的可拓展性.那么有没有想自己开发一 ...

  6. vue serve 部署 步骤说明

    1. 构建镜像 docker build -t 镜像名称:镜像TAG --build-arg URL=http://localhost:8081 --build-arg PORT=2000 --bui ...

  7. Cannot find loader com.jme3.scene.plugins.ogre.MeshLoader

    五月 20, 2022 2:46:07 下午 com.jme3.asset.AssetConfig loadText 警告: Cannot find loader com.jme3.scene.plu ...

  8. Mac m1 安装 scrcpy

    前提:已经安装 brew 1. 设定 HOMEBREW_BOTTLE_DOMAIN(不设定的时候 ,会遇到报错  Bottle missing, falling back to the default ...

  9. Coursera Self-driving1, introduction

    有哪些 Sensors? 摄像头和激光雷达,毫米波雷达等 sensor 分类: exteroceptive (surrounding), 有 camera(Resolution, FOV, Dynam ...

  10. 【JS设计模式笔记】-观察者模式(即发布-订阅模式)(结构型)

    发布-订阅模式的作用 比如常见的发送短信就是一个典型的发布-订阅模式,例如,小明.小红去售楼处购买房子,但是售楼处的工作人员告诉小明.小红当前楼盘已经售罄,新楼盘还没有开售,这个时候,小明.小红把自己 ...