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

Rust中临时修改不可变结构体是否安全?合规方案问询

关于Rust中临时修改不可变引用对象的安全性与实现方式

问题描述

我尝试编写如下代码,通过将不可变引用转换为原始指针并转为可变指针,临时修改不可变结构体后立即还原。请问这种指针转换操作是否安全?是否属于未定义行为?若仅持有不可变引用(需满足 trait 约束,无法使用可变引用或所有权转移),能否实现此类‘修改-读取-还原’的模式?若不可行,该如何实现?

示例代码

#[derive(Debug)]
struct Num(i32); // doesn't impl Copy

// prints one more than the input num
fn modify_read_undo(num: &Num) {
    let num_ptr = num as *const Num as *mut Num; // the scary part
    unsafe {
        (*num_ptr).0 += 1;
        println!("{:?}", *num_ptr);
        (*num_ptr).0 -= 1;
    }
}

fn main() {
    let num = Num(0);
    modify_read_undo(&num); // prints "Num(1)" as hoped for
}

注:与Stack Overflow上的类似问题不同,本场景是临时修改后立即还原,而非永久修改不可变结构体。

回答

1. 你的代码属于未定义行为,完全不安全

哪怕最终还原了原始值,这种操作依然违反了Rust的内存安全模型:

  • Rust的不可变引用&T代表共享只读访问,编译器会基于这个假设执行优化(比如常量折叠、将值缓存到寄存器、省略重复读取)。强制修改内存的操作会打破这个假设,导致生成的代码出现不可预测的结果——比如后续读取可能依然使用缓存的旧值,或者在多线程场景下引发数据竞争。
  • 未定义行为意味着程序可能在任何时候崩溃、输出错误结果,甚至出现更隐蔽的内存安全问题,且这类问题极难调试。

2. 仅持有不可变引用时,无法安全实现该模式

Rust的类型系统核心目标之一就是阻止这种“绕过不可变规则”的操作,因此仅靠不可变引用无法安全完成修改-读取-还原的流程。

3. 安全的替代方案

方案一:使用内部可变性(推荐)

如果能控制结构体的定义,通过Cell(单线程)或AtomicI32(多线程)赋予结构体内部可变性,这样就能在持有不可变引用的前提下安全修改内部值:

use std::cell::Cell;

#[derive(Debug)]
struct Num(Cell<i32>);

fn modify_read_undo(num: &Num) {
    let old_val = num.0.get();
    num.0.set(old_val + 1);
    // 打印修改后的值
    println!("Num({})", num.0.get());
    // 还原原始值
    num.0.set(old_val);
}

fn main() {
    let num = Num(Cell::new(0));
    modify_read_undo(&num); // 输出 Num(1)
}

Cell会在编译期确保单线程下的内存安全,完全符合Rust的规则,无需unsafe代码。

方案二:重构逻辑获取可变引用

如果无法修改结构体定义,需要重新设计代码流程,在需要修改的阶段获取&mut Num可变引用,确保满足Rust的独占性规则:

#[derive(Debug)]
struct Num(i32);

fn modify_read_undo(num: &mut Num) {
    num.0 += 1;
    println!("{:?}", num);
    num.0 -= 1;
}

fn main() {
    let mut num = Num(0);
    modify_read_undo(&mut num); // 输出 Num(1)
}

内容的提问来源于stack exchange,提问作者John Simon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:15:59