![](/img/trans.png)
[英]Cannot infer an appropriate lifetime for autoref due to conflicting requirements
[英]Creating a recursive list of references errors with "cannot infer an appropriate lifetime for autoref due to conflicting requirements"
該代碼的基本思想是創建一個包含符號的一些信息的分層結構Context
,並將一個Context
提供給一個Statement
結構中的 lambda 以獲得最終結果。 如果需要,可以從父級派生子級上下文:
use anyhow::Result; // 1.0.40
use std::{collections::HashMap, rc::Rc};
struct Context<'a> {
parent: Option<&'a mut Context<'a>>,
symbols: HashMap<String, i64>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Context {
parent: None,
symbols: HashMap::new(),
}
}
fn derive(&'a mut self) -> Self {
Context {
parent: Some(self),
symbols: HashMap::new(),
}
}
}
#[derive(Clone)]
struct Statement {
execute: Rc<dyn Fn(&mut Context) -> Result<()>>,
}
struct Node {
cond: Statement,
stmts: Vec<Statement>,
}
impl Node {
fn get(&self) -> Statement {
let cond = self.cond.clone();
let stmts = self.stmts.clone();
Statement {
execute: Rc::new(move |ctx| {
(cond.execute)(ctx)?;
let mut cctx = ctx.derive();
for stmt in stmts {
(stmt.execute)(&mut cctx)?;
}
Ok(())
}),
}
}
}
當我編譯這段代碼時,我得到了錯誤:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:42:36
|
42 | let mut cctx = ctx.derive();
| ^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 40:30...
--> src/lib.rs:40:30
|
40 | execute: Rc::new(move |ctx| {
| ______________________________^
41 | | (cond.execute)(&mut ctx)?;
42 | | let mut cctx = ctx.derive();
43 | | for stmt in stmts {
... |
46 | | Ok(())
47 | | }),
| |_____________^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:42:32
|
42 | let mut cctx = ctx.derive();
| ^^^
note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the body at 40:30...
--> src/lib.rs:40:30
|
40 | execute: Rc::new(move |ctx| {
| ______________________________^
41 | | (cond.execute)(&mut ctx)?;
42 | | let mut cctx = ctx.derive();
43 | | for stmt in stmts {
... |
46 | | Ok(())
47 | | }),
| |_____________^
note: ...so that the types are compatible
--> src/lib.rs:42:36
|
42 | let mut cctx = ctx.derive();
| ^^^^^^
= note: expected `&mut Context<'_>`
found `&mut Context<'_>`
我發現這個錯誤信息是無用的。 我該如何解決這個錯誤?
根據您當前對execute
的定義,由於生命周期省略規則, Context
和&mut
參數的生命周期暗示不同,但您在閉包中使用.derive()
要求它們相同。
dyn Fn(&'a mut Context<'b>) -> Result<()>
您可以通過使用更高級別的特征來解決此問題,該特征綁定到引入命名生命周期以將它們鏈接在一起:
dyn for<'a> Fn(&'a mut Context<'a>) -> Result<()>
但是,解決這個問題並使for
循環不消耗stmts
( playground ),您仍然會遇到終身問題:
error[E0499]: cannot borrow `*ctx` as mutable more than once at a time
--> src/lib.rs:42:32
|
40 | execute: Rc::new(move |ctx| {
| --- has type `&'1 mut Context<'1>`
41 | (cond.execute)(ctx)?;
| -------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*ctx` is borrowed for `'1`
42 | let mut cctx = ctx.derive();
| ^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `cctx` as mutable more than once at a time
--> src/lib.rs:44:36
|
40 | execute: Rc::new(move |ctx| {
| --- has type `&'1 mut Context<'1>`
...
44 | (stmt.execute)(&mut cctx)?;
| ---------------^^^^^^^^^-
| | |
| | `cctx` was mutably borrowed here in the previous iteration of the loop
| argument requires that `cctx` is borrowed for `'1`
為什么這個可變借用超出了它的 scope? 簡而言之,不要做&'a mut Context<'a>
,它會對試圖使不同的生命周期對齊的借用檢查器造成嚴重破壞,並且不可避免地會導致令人困惑的錯誤。
特別是使用可變引用受到更多限制,因此您可以通過使用不可變引用&'a Context<'a>
來擺脫它,但取決於您打算做什么,這可能不是一個選擇。 如果您需要可變性,您可能不得不通過Rc
和RefCell
訴諸共享所有權和內部可變性。
所以問題與生命周期有關,但這還不是唯一的問題。
首先,每當我遇到閉包錯誤和奇怪的編譯器消息時,我會暫時將閉包替換為實際的 function,因為這往往會使某些錯誤消息更容易解析。
然后我嘗試將顯式生命周期參數添加到代碼中的許多其他部分:
use anyhow::Result; // 1.0.40
use std::{collections::HashMap, rc::Rc};
struct Context<'a> {
parent: Option<&'a mut Context<'a>>,
symbols: HashMap<String, i64>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Context {
parent: None,
symbols: HashMap::new(),
}
}
fn derive(&'a mut self) -> Context<'a> {
Context {
parent: Some(self),
symbols: HashMap::new(),
}
}
}
#[derive(Clone)]
struct Statement<'a> {
execute: Rc<(dyn Fn(&'a mut Context<'a>) -> Result<()> + 'a)>,
}
struct Node<'a> {
cond: Statement<'a>,
stmts: Vec<Statement<'a>>,
}
impl<'a> Node<'a> {
fn get(&self) -> Statement<'a> {
let cond = self.cond.clone();
let stmts = self.stmts.clone();
Statement {
execute: Rc::new(move |ctx| {
(cond.execute)(ctx)?;
let mut cctx = ctx.derive();
for stmt in stmts {
(stmt.execute)(&mut cctx)?;
}
Ok(())
}),
}
}
}
這解決了生命周期問題,但也存在許多其他問題:您慷慨地使用可變引用(可變借用),當然現在編譯器抱怨您不止一次地可變地借用,因為您的生命周期需要引用活得夠久!
這里的問題是您需要同時保持對給定上下文的多個可變引用,這是 Rust 不允許的。
這個難題的解決方案不是試圖破解當前的結構,而是重新考慮是否真的需要所有這些可變引用,以及是否也可以以其他方式重新編寫代碼。
從其他面向 object 的語言來看,這種“對象之海”具有很多(當然是可變的)來回指向的引用是很常見的,但是 Rust 不太喜歡那樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.