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

如何修改Rust中可变引用结构体的字段值?

Rust 修改可变引用结构体字段的问题

问题场景

在项目的query_construction函数中,参数类型为Option<&'a mut PlayerConditions>,需要按以下逻辑修改字段:

  • 若condition为None,添加一个设置了set_email(None)的PlayerConditions实例
  • 若condition为Some且email为None,设置set_email(None)
  • 若condition为Some且email为Some,不做任何操作

尝试了以下代码:

condition = Some(
    &mut condition
        .unwrap_or(&mut PlayerConditions::new())
        .set_email(None),
);

出现编译错误:

error[E0384]: cannot assign to immutable argument `condition`
  --> src\main.rs:72:9
   |
59 |           condition: Option<&'a mut PlayerConditions>,
   |           --------- help: consider making this binding mutable: `mut condition`
...
72 | /         condition = Some(
73 | |             &mut condition
74 | |                 .unwrap_or(&mut PlayerConditions::new())
75 | |                 .set_email(None),
76 | |         );
   | |_________^ cannot assign to immutable argument

不想将参数设为可变绑定,希望直接修改可变引用指向的结构体字段,完整代码如下:

#[derive(Debug, Default)]
pub struct PlayerConditions {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl PlayerConditions {
    pub fn new() -> Self {
        Self::default()
    }
    pub fn is_default(&self) -> bool {
        self.id.is_none() && self.name.is_none() && self.email.is_none()
    }
    pub fn id(&self) -> &Option<String> {
        &self.id
    }
    pub fn set_id(mut self, id: Option<String>) -> Self {
        self.id = id;
        self
    }
    pub fn name(&self) -> &Option<String> {
        &self.name
    }
    pub fn set_name(mut self, name: Option<String>) -> Self {
        self.name = name;
        self
    }
    pub fn email(&self) -> &Option<String> {
        &self.email
    }
    pub fn set_email(mut self, email: Option<String>) -> Self {
        self.email = email;
        self
    }
}

#[derive(Debug, Default)]
pub struct PlayerListInput {
    pub condition: Option<PlayerConditions>,
    pub order: Option<String>, // This is not String: is a struct in real code
                               // other fields here...
}

#[derive(Debug)]
pub struct DBPlayer {
    pub id: String,
    pub name: Option<String>,
    pub email: Option<String>,
}

impl DBPlayer {
    fn query_construction<'a>(
        condition: Option<&'a mut PlayerConditions>,
        order: &Option<String>,
    ) -> String {
        let mut query = "SELECT * FROM players".to_string();

        // --->>>> I need to change condition here using this logic:

        // if condition is None add one condition with "set_email(None)"
        // if condition is Some and email == None set "set_email(None)"
        // if condition is Some and email == Some do nothing

        // I tried the below but it doesn't work:

        // condition = Some(
        //     &mut condition
        //         .unwrap_or(&mut PlayerConditions::new())
        //         .set_email(None),
        // );

        // From here it's ok

        if let Some(condition) = condition {
            if !condition.is_default() {
                // query = condition.add_each_one_to(query);
            }
        }

        if let Some(_order) = &order {
            // add order to query
        }

        query.to_string()
    }

    pub async fn query(
        _session: &str, // This is not String: is a struct in real code
        _db: &str,     // This is not String: is a connection/transaction in real code
        input: &mut PlayerListInput,
    ) -> Vec<DBPlayer> {
        // Check session here

        let _query = Self::query_construction(input.condition.as_mut(), &input.order);

        let players = vec![]; // fetch_them_from_db_using_query_here;

        players
    }
}

async fn players_from_repo(input: &mut PlayerListInput) -> Vec<DBPlayer> {
    DBPlayer::query("session", "db_connection", input).await
}

#[tokio::main]
async fn main() {
    let mut input = PlayerListInput::default();

    let players = players_from_repo(&mut input).await;

    dbg!(players);
}

解决方法

1. 修复Setter方法的所有权问题

当前的set_email等方法是消费自身并返回新实例,无法直接修改原引用的结构体。需要将这些方法改为可变引用方法,直接修改原对象:

impl PlayerConditions {
    // ... 保留其他方法 ...

    pub fn set_id(&mut self, id: Option<String>) -> &mut Self {
        self.id = id;
        self
    }

    pub fn set_name(&mut self, name: Option<String>) -> &mut Self {
        self.name = name;
        self
    }

    pub fn set_email(&mut self, email: Option<String>) -> &mut Self {
        self.email = email;
        self
    }
}

2. 调整参数类型以支持修改外部Option

原参数Option<&mut PlayerConditions>只能修改已存在的PlayerConditions实例,但无法将外部的None改为Some。需要将参数改为&mut Option<PlayerConditions>,这样才能直接操作外部的Option:

修改query_construction函数的参数和逻辑:

impl DBPlayer {
    fn query_construction<'a>(
        condition: &'a mut Option<PlayerConditions>,
        order: &Option<String>,
    ) -> String {
        let mut query = "SELECT * FROM players".to_string();

        // 实现需求逻辑
        match condition {
            None => {
                // 创建新实例并设置email为None
                *condition = Some(PlayerConditions::new().set_email(None));
            }
            Some(cond) => {
                if cond.email().is_none() {
                    // email已经是None,执行设置操作(逻辑上可省略,保留以明确需求)
                    cond.set_email(None);
                }
                // email是Some时不做操作
            }
        }

        // 后续逻辑保持不变
        if let Some(condition) = condition {
            if !condition.is_default() {
                // query = condition.add_each_one_to(query);
            }
        }

        if let Some(_order) = &order {
            // add order to query
        }

        query.to_string()
    }

    // 修改query方法中调用query_construction的方式
    pub async fn query(
        _session: &str,
        _db: &str,
        input: &mut PlayerListInput,
    ) -> Vec<DBPlayer> {
        // Check session here

        let _query = Self::query_construction(&mut input.condition, &input.order);

        let players = vec![];

        players
    }
}

逻辑说明

  • 当外部的condition是None时,直接创建新的PlayerConditions实例并赋值给外部的Option
  • 当外部的condition是Some时,检查email字段:如果是None则执行设置操作,是Some则跳过
  • 修改后的参数类型&mut Option<PlayerConditions>允许直接修改外部的Option状态,同时修改内部结构体的字段

内容的提问来源于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 19:13:15