如何创建具有对其自身类型的可选可变引用的 struct .不是自引用的,因此实例是不同的,例如

struct Environment<'a> {
    outer: Option<&'a mut Environment<'a>>,
    // Can be swapped for any other data
    variables: HashMap<Identifier, Expression>, 
}

我还try 过:

struct Environment<'a, 'b> {
    outer: Option<&'a mut Environment<'b, 'b>>, //...

但没有成功.

我希望能够:

  • 保留它作为引用(没有长方体),因为实例将在堆栈上
  • 保持它不会对运行时性能造成额外影响(RC/RefCell)
  • 在任意外部环境中改变variables
  • 不能更改outer.outer后面的值(因为我知道这可能会导致错误)
  • 保持内部环境的作用--只要外部环境存在,它就会悄悄地(排他地)borrow 外部环境(这样就不会有来自同一外部/父母的两个内部/子元素)

因此,这是一种拆分借款.其中,outer链上的variables个是借来的&mut,但outer&,Environment作为一个整体也是&mut‘d

我明白问题是&amp;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

推荐答案

问题是,你不需要一辈子.即使是两个也帮不上忙.您需要无限多个生命周期或一组动态生命周期来跟踪每个动态子对象.这当然行不通.

据我所知,你想要的东西不能用铁 rust 来写.

有了不安全的铁 rust ,就有可能做得很好,只要你不会改变outer指针.这不安全的原因是编译器无法证明这一点.有两种方法可以解决这种不安全 rust 病的问题.一种是将父指针存储为原始指针:

use std::collections::HashMap;
use std::marker::PhantomData;
use std::ptr::NonNull;

struct Environment<'a> {
    outer: Option<NonNull<Environment<'a>>>,
    value: HashMap<i32, String>,
    _marker: PhantomData<&'a ()>,
}

// Needed because of the `NonNull`, safe as long as the keys and values are `Send` and `Sync`.
unsafe impl Send for Environment<'_> {}
unsafe impl Sync for Environment<'_> {}

impl<'a> Environment<'a> {
    fn new() -> Self {
        Self {
            outer: None,
            value: HashMap::new(),
            _marker: PhantomData,
        }
    }

    fn child<'b>(&'b mut self) -> Environment<'b> {
        Self {
            outer: Some(self.into()),
            value: HashMap::new(),
            _marker: PhantomData,
        }
    }
    
    fn map_depth(&self, depth: u32) -> Option<&HashMap<i32, String>> {
        unsafe {
            let mut this = NonNull::from(self);
            for _ in 0..depth {
                this = this.as_ref().outer?;
            }
            Some(&this.as_ref().value)
        }
    }
    
    fn map_depth_mut(&mut self, depth: u32) -> Option<&mut HashMap<i32, String>> {
        unsafe {
            let mut this = NonNull::from(self);
            for _ in 0..depth {
                this = this.as_mut().outer?;
            }
            Some(&mut this.as_mut().value)
        }
    }
}

另一种更安全的方法是使用内部可变性:就像将值包装在RefCell中一样,只需使用UnsafeCell而不是RefCell来避免运行时开销:

use std::cell::UnsafeCell;
use std::collections::HashMap;

struct Environment<'a> {
    outer: Option<&'a Environment<'a>>,
    value: UnsafeCell<HashMap<i32, String>>,
}

// Needed because of the `UnsafeCell`, safe as long as the keys and values are `Sync`.
unsafe impl Sync for Environment<'_> {}

impl<'a> Environment<'a> {
    fn new() -> Self {
        Self {
            outer: None,
            value: UnsafeCell::new(HashMap::new()),
        }
    }

    fn child<'b>(&'b mut self) -> Environment<'b> {
        Environment {
            outer: Some(self),
            value: UnsafeCell::new(HashMap::new()),
        }
    }

    fn map_depth(&self, depth: u32) -> Option<&HashMap<i32, String>> {
        let mut this: &Environment = self;
        for _ in 0..depth {
            this = this.outer?;
        }
        Some(unsafe { &*this.value.get() })
    }

    fn map_depth_mut(&mut self, depth: u32) -> Option<&mut HashMap<i32, String>> {
        let mut this: &Environment = self;
        for _ in 0..depth {
            this = this.outer?;
        }
        Some(unsafe { &mut *this.value.get() })
    }
}

Rust相关问答推荐

为什么父作用域中的变量超出了子作用域

计算具有相邻调换且没有插入或删除的序列的距离

什么样的 struct 可以避免使用RefCell?

限制未使用的泛型导致编译错误

使用Clap时如何将String作为Into Str参数传递?

Rust&;Tokio:如何处理更多的信号,而不仅仅是SIGINT,即SIGQUE?

关于 map 闭合求和的问题

通过RabbitMQ取消铁 rust 中长时间运行的人造丝任务的策略

返回Result<;(),框<;dyn错误>>;工作

由于生存期原因,返回引用的闭包未编译

为什么不';t(&;mut-iter).take(n)取得iter的所有权?

我可以解构self 参数吗?

`use` 和 `crate` 关键字在 Rust 项目中效果不佳

是否可以通过可变引用推进可变切片?

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

判断对象是 PyDatetime 还是 Pydate 的实例?

在单独的线程上运行 actix web 服务器

Rust - 在线程之间不安全地共享没有互斥量的可变数据

Rust:如果我知道只有一个实例,那么将可变borrow 转换为指针并返回(以安抚borrow 判断器)是否安全?

`if let` 只是另一种编写其他 `if` 语句的方式吗?