如何修复Rust中从共享引用对象创建新对象的报错问题
Rust编译错误E0507的原因与修复方案
问题代码
#[derive(Default)] struct OtherBigStruct { pub big_field: Option<String>, } #[derive(Default)] struct Player { pub name: Option<String>, pub other_big_struct: Box<OtherBigStruct>, } #[tokio::main] async fn main() { let first: &Option<Box<Player>> = &Some(Box::new(Player { name: Some("Bob".to_string()), other_big_struct: Box::new(OtherBigStruct { big_field: Some("field".to_string()), }), })); let mut _new_one = Player::default(); if 1 == 1 { // some condition if let Some(first_player) = first { _new_one = Player { ..**first_player } } } }
报错信息
Compiling playground v0.0.1 (/playground) error[E0507]: cannot move out of `first_player.name` which is behind a shared reference --> src/main.rs:26:24 | 26 | _new_one = Player { ..**first_player } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `first_player.name` has type `Option<String>`, which does not implement the `Copy` trait error[E0507]: cannot move out of `first_player.other_big_struct` which is behind a shared reference --> src/main.rs:26:24 | 26 | _new_one = Player { ..**first_player } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `first_player.other_big_struct` has type `Box<OtherBigStruct>`, which does not implement the `Copy` trait For more information about this error, try `rustc --explain E0507`. error: could not compile `playground` (bin "playground") due to 2 previous errors
错误原因
错误核心是无法从共享引用指向的值中移动所有权:
first是&Option<Box<Player>>类型,两次解引用**first_player后得到Player的共享引用(&Player)。Player的name(Option<String>)和other_big_struct(Box<OtherBigStruct>)都未实现Copytrait,结构体更新语法..**first_player会尝试直接移动这些字段的所有权。- Rust的内存安全规则禁止从共享引用后移动值,否则会导致原引用指向的内容失效,产生悬垂引用风险。
修复方案
由于仅允许修改let mut _new_one = Player::default();之后的代码,提供两种可行修复方式:
方案1:手动克隆每个字段
通过克隆非Copy类型的字段获取新所有权,避免移动原引用的值:
let mut _new_one = Player::default(); if 1 == 1 { // some condition if let Some(first_player) = first { let player_ref = &**first_player; _new_one = Player { name: player_ref.name.clone(), other_big_struct: Box::new(OtherBigStruct { big_field: player_ref.other_big_struct.big_field.clone(), }), }; } }
方案2:利用Clone trait简化克隆(若允许调整结构体定义)
如果可以修改结构体定义(添加Clone派生),可直接克隆整个Player实例:
// 先修改结构体定义(若允许) #[derive(Default, Clone)] struct OtherBigStruct { pub big_field: Option<String>, } #[derive(Default, Clone)] struct Player { pub name: Option<String>, pub other_big_struct: Box<OtherBigStruct>, } // 后续代码中使用clone let mut _new_one = Player::default(); if 1 == 1 { // some condition if let Some(first_player) = first { _new_one = (**first_player).clone(); } }
注:若严格限制只能修改
let mut _new_one之后的代码,则只能使用方案1。
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

