【发布时间】:2022-08-19 17:59:00
【问题描述】:
我想要一个名为 Outcome 的结构,它包含对实体的引用。然后我想找到它指向的实体,可变地借用它并根据 Outcome 的效果改变它。我的代码现在看起来像这样
fn main() {
let mut entities = vec![
Entity {
name: \"George\".to_string(),
current_hp: 200.0,
damage: 10.0,
},
Entity {
name: \"Jacob\".to_string(),
current_hp: 100.0,
damage: 5.0,
},
];
let outcome = Outcome {
caster: &entities[0],
target: &entities[1],
effect: Effect::Damage(entities[0].damage),
};
match outcome.effect {
Effect::Damage(amount) => {
outcome.target.current_hp -= amount;
}
}
}
这当然行不通,因为我正在尝试修改不可变引用。当我在范围内有可变向量时,我可以以某种方式将不可变引用转换为可变引用吗?或者是否有更生疏的方法来解决这个问题?
(对于信息,Outcome 是一个函数返回的结构,我将不可变的引用传递给它,并将它们返回并产生效果)。
我发现唯一可行的解决方案是在这样的不安全块中更改不可变引用
match outcome.effect {
Effect::Damage(amount) => unsafe {
let target = outcome.target as *const Entity as *mut Entity;
(*target).current_hp -= amount;
},
}
-
如果你想通过一个引用发生变异,它必须是一个可变引用。这是绝不从不可变引用中获取可变引用是安全的,除非它通过
UnsafeCell发生。 -
(或者显然是基于
UnsafeCell的安全抽象,例如RefCell) -
请注意,
&UnsafeCell<T> -> &mut UnsafeCell<T>转换也不可靠。只有&UnsafeCell<T> -> &mut T可以,如果正确检查了结果引用的唯一性。 -
Outcome 不能保存可变的 refs 吗?