最近,在使用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. vue之插槽-slot

    1.背景 2.slot简单使用 <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  2. 什么是MMU

    一.MMU的定义   MMU是Memory Management Unit的缩写,中文名是内存管理单元,有时也称作分页内存管理单元(Paged Memory Management Unit,缩写为PM ...

  3. 神经网络之卷积篇:详解卷积步长(Strided convolutions)

    详解卷积步长 卷积中的步幅是另一个构建卷积神经网络的基本操作,让向展示一个例子. 如果想用3×3的过滤器卷积这个7×7的图像,和之前不同的是,把步幅设置成了2.还和之前一样取左上方的3×3区域的元素的 ...

  4. 【全】CSS动画大全之按钮【a】

    效果预览 代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> < ...

  5. 3. EMC EMS EMI

    1. 定义 1.1 EMC(Electromagnetic Compatibility) 电磁兼容性(EMC)是指系统正常工作的能力,不受其正常环境中电磁现象的干扰,不产生干扰其他设备的电干扰. 1. ...

  6. 13. Advanced-control timers (TIM1 and TIM8)

    1. 基本介绍 有三个基础的寄存器: 计数寄存器(TIMx_CNT,Counter register) 预分频寄存器(TIMx_PSC,Prescaler register) 自动重载寄存器(TIMx ...

  7. PPT或Visio比较舒适的RGB配色参数

    1.187 204 235 2.222 156 83 3.117 156 83 4.64 116 52 5.117 121 74 6.69 137 148 7.182 194 154 8.207 19 ...

  8. 如何使用 Shebang

    什么是 Shebang? 简单来说,就是你在脚本开头看到的这个: #!/usr/bin/bash Shebang(也称为 hash-bang.pound-bang 或者 bang)是一个作为脚本文件中 ...

  9. 在 Mac 上使用 X11

    有时我们需要在服务器上运行一个 GUI 程序,然而我们是通过 SSH 连接到服务器的,看不到图形界面,怎么办呢?我们可以通过 X11 将 GUI 程序的界面转发到本地. 在 Mac 上使用 X11 需 ...

  10. the request was rejected because no multipart boundary was found

    报错: Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.t ...