我正在尝试创建类似于下面代码的内容。鉴于我只是暂时修改不可变结构(我撤消了所做的更改),这样转换原始指针是否安全?
#[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
}
在这个小例子中,一切似乎都按其应有的方式工作,但我担心这是某种未定义的行为,只是目前恰好在工作。如果只需要一个不可变的引用,这种函数是否可能?如果不是,如何实现类似的模式(修改、读取、撤消)?
我知道如果我使用可变引用或只是取得所有权,这可能会起作用 - 我特别感兴趣的是使用不可变引用(以满足特征边界)来使其工作。如果有必要,我可以发布完整的代码,但这个示例很好地演示了我想要的内容。
注意:有没有办法使不可变引用可变?类似,但不完全相同,因为它们永久更改不可变结构,而我在进行更改后立即撤消更改。
这是一个使用
RefCell
的简单示例:
use std::cell::RefCell;
#[derive(Debug)]
struct Num(RefCell<i32>); // Use RefCell for interior mutability
// The function takes an immutable reference
fn modify_read_undo(num: &Num) {
{
// Borrow the value mutably inside this scope
let mut num_borrowed = num.0.borrow_mut();
*num_borrowed += 1;
// The mutable borrow ends here, so the next line is safe
}
// Print the value
println!("{:?}", num);
{
// Borrow the value mutably again to undo the change
let mut num_borrowed = num.0.borrow_mut();
*num_borrowed -= 1;
}
}
fn main() {
let num = Num(RefCell::new(0));
modify_read_undo(&num);
// The original value of num is preserved
println!("{:?}", num); // prints "Num(RefCell { value: 0 })"
}