Rust,如何返回对结构中持续时间与结构相同的内容的引用?

Rust,如何返回对结构中持续时间与结构相同的内容的引用?,rust,lifetime,Rust,Lifetime,我正在移植一个我写给Rust的编译器。在其中,我有一个enum实体,它表示函数和变量之类的东西: 发布枚举实体) //以后还有更多的空间。 } 然后我有一个structScope,负责在散列映射中保存这些实体,其中键是程序员给实体的名称。(例如,声明名为sin的函数会将实体放入键sin处的哈希映射中) 发布结构范围>, 家长:选项> } 我希望能够获得HashMap中对象的只读引用,以便可以从其他数据结构中引用它。例如,当我解析函数调用时,我希望能够存储对正在调用的函数的引用,而不仅仅是存储

我正在移植一个我写给Rust的编译器。在其中,我有一个enum
实体
,它表示函数和变量之类的东西:

发布枚举实体)
//以后还有更多的空间。
}
然后我有一个struct
Scope
,负责在散列映射中保存这些实体,其中键是程序员给实体的名称。(例如,声明名为
sin
的函数会将
实体
放入键
sin
处的哈希映射中)

发布结构范围>,
家长:选项>
}
我希望能够获得HashMap中对象的只读引用,以便可以从其他数据结构中引用它。例如,当我解析函数调用时,我希望能够存储对正在调用的函数的引用,而不仅仅是存储函数的名称,并且每次需要与名称对应的实际
实体
对象时都必须查找引用。为此,我采用了以下方法:

impl{
发布fn查找(&self,符号:&str)->选项>{
让结果=self.symbols.get(symbol);
比赛结果{
选项::无=>匹配self.parent{
选项::无=>选项::无,
选项::Some(parent)=>parent.lookup(符号),
},
选项::某些(_值)=>结果
}
}
}
但是,这会导致编译错误:

错误[E0495]:由于需求冲突,无法推断自动引用的适当生存期
-->src/vague/scope.rs:29:31
|
29 |让结果=self.symbols.get(symbol);
|                               ^^^
|
注意:首先,生命周期不能超过方法体上28:3定义的匿名生命周期#1。。。
-->src/vague/scope.rs:28:3
|
28 |/pub fn查找(&self,symbol:&str)->选项>{
29 | |让结果=self.symbols.get(symbol);
30 | |匹配结果{
31 | |选项::无=>匹配self.parent{
...  |
36 | |     }
37 | |   }
| |___^
注意:…这样引用就不会超过借用的内容
-->src/vague/scope.rs:29:18
|
29 |让结果=self.symbols.get(symbol);
|                  ^^^^^^^^^^^^
注意:但是,生存期必须对impl上9:6定义的生存期“a”有效。。。
-->src/vague/scope.rs:9:6
|
9 | impl{
|      ^^
=注意:…因此表达式是可赋值的:
预期标准::选项::选项>
找到std::option::option>{
但这意味着引用的有效期不够长,因此我无法将其放入结构或任何其他类型的存储中,这些存储将超出调用
lookup
的范围。另一种解决方案是:

pub fn lookup(&self,symbol:&str)->Option
导致上一个编译器错误,因为函数从中获取
实体的唯一位置是哈希映射,哈希映射定义为具有
实体选项>{
这意味着
lookup
只能调用一次,这显然是一个问题。我以前的理解是错误的,但问题仍然是要求对
self
的引用与整个对象具有相同的生存期严重限制了代码,因为我无法从具有任何更短的生命周期,例如,作为函数参数传入的生命周期或在循环中创建的生命周期


我如何着手解决这个问题?是否有某种方法可以解决我现在所拥有的功能,或者我是否需要以完全不同的方式实现我正在寻找的行为?以下是您想要的签名:

pub fn lookup(&self, symbol: &str) -> Option<&'a Entity<'a>>
这段代码是因为它必须:没有编译器可以用来证明它错误的生存期约束,因为
foo
的生存期不与
sc
的借用相耦合。但是很明显,如果
lookup
是按照您第一次尝试的方式实现的,
foo
将在
drop(sc)之后包含一个悬空指针
,这就是编译器拒绝它的原因

您必须重新设计数据结构,以使
查找
的给定签名生效。鉴于问题中的代码,目前尚不清楚如何最好地执行此操作,但以下是一些想法:

  • 范围中的生存期解耦
    ,以便借用
    父项
    的生存期不同于
    符号
    。然后进行
    查找
    获取
    和父项自身
    ,这可能本身不起作用,具体取决于您需要对
    实体
    执行什么操作,但您可能无法使用如果您需要区分不同数据的生命周期,则可以执行此操作

    pub struct Scope<'parent, 'sym> {
        symbols: HashMap<String, Entity<'sym>>,
        parent: Option<&'parent Scope<'parent, 'sym>>,
    }
    
    impl<'parent, 'sym> Scope<'parent, 'sym> {
        pub fn lookup(&'parent self, symbol: &str) -> Option<&'parent Entity<'sym>> {
            /* ... */
        }
    }
    
    pub结构范围{
    符号:HashMap,
    }
    impl范围{
    发布fn查找(&'parent self,symbol:&str)->Option>{
    /* ... */
    }
    }
    
  • 将你的
    范围
    和/或你的
    实体
    存储在竞技场中。竞技场可以发出比
    自我
    -借用更久的引用,只要它们不超过竞技场数据结构本身。折衷是,在整个竞技场被摧毁之前,竞技场中的任何内容都不会被释放。它不能替代garbage集合

  • 使用
    Rc
    Arc
    存储你的
    范围和/或你的
    实体和/或任何包含引用的
    实体的数据。这是一种完全消除生存期参数的方法,但运行时成本很小

pub struct Scope<'parent, 'sym> {
    symbols: HashMap<String, Entity<'sym>>,
    parent: Option<&'parent Scope<'parent, 'sym>>,
}

impl<'parent, 'sym> Scope<'parent, 'sym> {
    pub fn lookup(&'parent self, symbol: &str) -> Option<&'parent Entity<'sym>> {
        /* ... */
    }
}