You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复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>)都未实现Copy trait,结构体更新语法..**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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:30:31