如何创建一个具有对其自身类型的可选可变引用的结构。不是自我引用,所以实例不同,例如
struct Environment<'a> {
outer: Option<&'a mut Environment<'a>>,
// Can be swapped for any other data
variables: HashMap<Identifier, Expression>,
}
我也尝试过:
struct Environment<'a, 'b> {
outer: Option<&'a mut Environment<'b, 'b>>, //...
但没有成功。
我希望能够:
variables
outer.outer
背后的值(据我所知这可能会导致不健全)这是一种分割借用。
variables
链上的outer
是借用的&mut
,但outer
是&
,而Environment
作为一个整体也是&mut
'd
我知道问题在于 &mut T 对 T 是不变的。有什么方法可以使
&mut T
变得协变,就像它是 &T
一样吗?
编辑: 所需的示例用法(无法编译)
struct Environment<'a> {
outer: Option<&'a mut Environment<'a>>,
value: i32,
}
impl<'a> Environment<'a> {
fn new(value: i32) -> Self {
Self { outer: None, value }
}
fn child<'b>(&'b mut self, value: i32) -> Environment<'b>
where
// This is the relationship I would want
// parent environment outlives child environment
'a: 'b
{
Self { outer: Some(self), value }
}
}
fn user_that_creates_child(env: &mut Environment) {
let child_env = env.child(11);
// Do something with the child
child_env.outer.unwrap().value = 8; // This should be possible
// child_env.outer.unwrap().outer = // This shouldn't be
}
fn main() {
let mut root_env = Environment::new(7);
}
编译器建议与我想要的关系相反,即子函数的
where 'b: 'a
这是可行的解决方案:
struct Environment<'a> {
outer: Option<&'a mut Environment<'a>>,
value: i32,
}
impl<'a> Environment<'a> {
fn new(value: i32) -> Self {
Self { outer: None, value }
}
// Lifetime 'a is enough here.
fn child(&'a mut self, value: i32) -> Environment<'a> {
Self {
outer: Some(self),
value,
}
}
}
// In the original example, the compiler coerced
// &mut Environment into &'a mut Environment<'b>, that
// doesn't feet the `child` method requirements.
fn user_that_creates_child<'a>(env: &'a mut Environment<'a>) {
let child_env = env.child(11);
child_env.outer.unwrap().value = 8;
}
fn main() {
let mut root_env = Environment::new(7);
user_that_creates_child(&mut root_env); // Compiles!
}
编写的代码的问题是,
outer
指针定义了子结构的生命周期。
因此每个孩子都必须与外部环境生活在一起。为子环境和外部环境定义多重生命周期没有任何意义,并且会导致不同的编译器错误。
由于您不希望能够更改外部值,但可以复制可复制的值,因此最好的解决方案应该是使用
Cell
,它提供了零抽象解决方案。
use std::cell::Cell;
struct Environment<'a> {
outer: Option<&'a Environment<'a>>,
value: Cell<i32>,
}
impl<'a> Environment<'a> {
fn new(value: i32) -> Self {
Self { outer: None, value: Cell::new(value) }
}
fn child(&'a self, value: i32) -> Environment<'a>
{
Self { outer: Some(self), value: Cell::new(value) }
}
}
fn user_that_creates_child(env: &mut Environment) {
let child_env = env.child(11);
// Do something with the child
child_env.outer.unwrap().value.set(8); // This should be possible
// child_env.outer.unwrap().outer = // This shouldn't be
}
fn main() {
let mut root_env = Environment::new(7);
user_that_creates_child(&mut root_env);
}