Rust的Reborrow机制

打印 上一主题 下一主题

主题 984|帖子 984|积分 2954

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
最近,在使用Rust时遇到了Reborrow的概念,纪录下来以备以后参考。
1. 起因

起因准备对数据进行Min-Max尺度化处理,也就是将一系列数据映射到一个新的范围。
首先,需要遍历数据,找出其中的最大值最小值,然后通过公式改变原始数据集的值。
Min-Max公式:尺度化后的值 = (原始值 - 最小值) / (最大值 - 最小值)
简化后的代码如下:
  1. fn main() {
  2.     let mut values = vec![10.5, 22.3, 103.5, 45.75];
  3.     let v = &mut values;
  4.     println!("原始数据: {:#?}", v);
  5.     let mut max = f64::MIN;
  6.     let mut min = f64::MAX;
  7.     for n in v {
  8.         if *n > max {
  9.             max = *n;
  10.         }
  11.         if *n < min {
  12.             min = *n;
  13.         }
  14.     }
  15.     println!("max is {}", max);
  16.     println!("min is {}", min);
  17.     println!("开始Min-Max标准化处理...");
  18.     for n in v {
  19.         *n = (*n - min) / (max - min);
  20.     }
  21.     println!("处理后数据: {:#?}", values);
  22. }
复制代码
运行时有如下错误:
  1. error[E0382]: use of moved value: `v`                                                                     
  2.    --> src/main.rs:22:14
  3.     |
  4. 3   |     let v = &mut values;
  5.     |         - move occurs because `v` has type `&mut Vec<f64>`, which does not implement the `Copy` trai
  6. t
  7. ...
  8. 9   |     for n in v {
  9.     |              - `v` moved due to this implicit call to `.into_iter()`
  10. ...
  11. 22  |     for n in v {
  12.     |              ^ value used here after move
  13.     |
复制代码
大概是第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)。
修改后再次运行代码:
  1. $  cargo run
  2. 原始数据: [
  3.     10.5,
  4.     22.3,
  5.     103.5,
  6.     45.75,
  7. ]
  8. max is 103.5
  9. min is 10.5
  10. 开始Min-Max标准化处理...
  11. 处理后数据: [
  12.     0.0,
  13.     0.12688172043010754,
  14.     1.0,
  15.     0.3790322580645161,
  16. ]
复制代码
values中的数据可以正常转换了。
注意,这里是将vReborrow成一个不可变借用&*v,因为我第一次遍历时不需要改变v。
如果想vReborrow成一个可变借用,可以写成:&mut *v。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

祗疼妳一个

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表