简体   繁体   English

Rust借用语义字符串

[英]Rust Borrow Semantics String

I have a block of code 我有一段代码

let mut current_room = None;

for (ref room_id, ref poker_room) in &self.planning_pokers {
    if poker_room.has_player(user_id.clone()) {
        current_room = Some(room_id.clone());
        break
    }
}

match current_room {
    Some(room_id) => {
        self.planning_pokers.get_mut(&room_id.clone()).unwrap().remove_player(user_id.clone());
        if self.planning_pokers.is_empty() {
            self.planning_pokers.remove(&room_id.clone());
        }
    },
    None => (),
    _ => ()
}

println!("Player {} joined room {}", join_room.room_id.clone(), user_id.clone());
if self.planning_pokers.contains_key(&join_room.room_id.clone()) {

}

This fails to compile due to a mutable and immutable borrow conflict. 由于可变和不可变的借用冲突,因此无法编译。 The conflict in question pertains to me setting the value of current_room to Some(room_id.clone()) . 有问题的冲突与我将current_room的值设置为Some(room_id.clone()) If I instead do Some(room_id.clone().to_string()) everything works as expected. 如果我改为执行Some(room_id.clone().to_string())一切正常。 Why is this the case? 为什么会这样呢? And why does the rust compiler give me an error that is seemingly unrelated? 为何rust编译器给我一个看似无关的错误?

For reference this is the error: 供参考,这是错误:

cannot borrow self.planning_pokers as mutable because it is also borrowed as immutable 不能将self.planning_pokers借为可变的,因为它也被借为不可变的

It looks like room_id is a double reference of type &&T . 看起来room_id&&T类型的双重引用。 This means that in Some(room_id.clone()) , you are cloning a borrowed reference to data that self.planning_pokers owns, rather than cloning the underlying data itself. 这意味着在Some(room_id.clone()) ,您正在克隆self.planning_pokers拥有的数据的借用引用 ,而不是克隆基础数据本身。 Because you then assign it to the variable current_room in the outer scope, self.planning_pokers remains borrowed throughout. 因为您然后将其分配给外部作用域中的变量current_room ,所以self.planning_pokers始终保持借用状态。 It might help to see that in this case, current_room is of type Option<&T> . 在这种情况下, current_room的类型为Option<&T>可能会有所帮助。

Some(room_id.to_string()) instead creates a copy of the underlying data which is moved into current_room . Some(room_id.to_string())会创建基础数据的副本,该副本将被移到current_room In this case current_room is of type Option<T> . 在这种情况下, current_room的类型为Option<T>

The difference is (I believe) due to Rust's auto-dereferencing behaviour . (我相信)差异是由于Rust的自动引用行为 Immutable references implement Clone , and so Rust calls the method on &T . 不可变的引用实现Clone ,因此Rust调用&T上的方法。 However, they do not implement ToString , so Rust dereferences all the way down to T . 但是,它们没有实现ToString ,因此Rust一直取消对T引用。


Note: rust-clippy warns about this very issue. 注意: rust-clippy会就此问题发出警告。 From the wiki : 维基

clone_double_ref clone_double_ref

What it does: Checks for usage of .clone() on an &&T. 它的作用:检查&& T上.clone()的使用。

Why is this bad? 为什么这样不好? Cloning an &&T copies the inner &T, instead of cloning the underlying T. 克隆&& T会复制内部的&T,而不是克隆基础T。

Example: 例:

fn main() {
   let x = vec![1];
   let y = &&x;
   let z = y.clone();
   println!("{:p} {:p}",*y, z); // prints out the same pointer
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM