gpt4 book ai didi

rust - 分配的匿名与结构生命周期

转载 作者:行者123 更新时间:2023-11-29 08:16:09 25 4
gpt4 key购买 nike

对于这段代码(修剪了一些,对不起,没有更多),我遇到了一生的问题:

fn main() {
println!("Hello, world!");
}

#[derive(Debug)]
pub struct Token<'a> {
pub line: usize,
// Col in code points.
pub col: usize,
// Index in bytes.
pub index: usize,
pub state: TokenState,
pub text: &'a str,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TokenState {
VSpace,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ParseState {
Expr,
}

pub struct Node<'a> {
kids: Vec<Node<'a>>,
state: ParseState,
token: Option<&'a Token<'a>>,
}

impl<'a> Node<'a> {
fn new(state: ParseState) -> Node<'a> {
Node {
kids: vec![],
state,
token: None,
}
}

fn new_token(token: &'a Token<'a>) -> Node<'a> {
// TODO Control state? Some token state?
Node {
kids: vec![],
state: ParseState::Expr,
token: Some(&token),
}
}

fn push_if(&mut self, node: Node<'a>) {
if !node.kids.is_empty() {
self.kids.push(node);
}
}
}

pub fn parse<'a>(tokens: &'a Vec<Token<'a>>) -> Node<'a> {
let mut root = Node::new(ParseState::Expr);
let mut parser = Parser {
index: 0,
tokens: tokens,
};
parser.parse_block(&mut root);
root
}

struct Parser<'a> {
index: usize,
tokens: &'a Vec<Token<'a>>,
}

impl<'a> Parser<'a> {
fn parse_block(&mut self, parent: &mut Node) {
loop {
let mut row = Node::new(ParseState::Expr);
match self.peek() {
Some(_) => {
self.parse_row(&mut row);
}
None => {
break;
}
}
parent.push_if(row);
}
}

fn parse_row(&mut self, parent: &mut Node) {
loop {
match self.next() {
Some(ref token) => match token.state {
TokenState::VSpace => break,
_ => {
parent.kids.push(Node::new_token(&token));
}
},
None => break,
}
}
}

fn next(&mut self) -> Option<&Token> {
let index = self.index;
if index < self.tokens.len() {
self.index += 1;
}
self.tokens.get(index)
}

fn peek(&mut self) -> Option<&Token> {
self.tokens.get(self.index)
}
}

( playground )

这是错误信息:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:90:24
|
90 | match self.next() {
| ^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 72:1...
--> src/main.rs:72:1
|
72 | / impl<'a> Parser<'a> {
73 | | fn parse_block(&mut self, parent: &mut Node) {
74 | | loop {
75 | | let mut row = Node::new(ParseState::Expr);
... |
112| | }
113| | }
| |_^
note: ...so that the type `Parser<'a>` is not borrowed for too long
--> src/main.rs:90:19
|
90 | match self.next() {
| ^^^^
note: but, the lifetime must be valid for the anonymous lifetime #3 defined on the method body at 88:5...
--> src/main.rs:88:5
|
88 | / fn parse_row(&mut self, parent: &mut Node) {
89 | | loop {
90 | | match self.next() {
91 | | Some(ref token) => match token.state {
... |
99 | | }
100| | }
| |_____^
note: ...so that expression is assignable (expected Node<'_>, found Node<'_>)
--> src/main.rs:94:42
|
94 | parent.kids.push(Node::new_token(&token));
| ^^^^^^^^^^^^^^^^^^^^^^^

所有引用都应该绑定(bind)到相同的外部生命周期。在我的完整代码中(我只是在这里摘录了一部分),我希望保留原始的已解析源代码,并且我正在尝试将所有内容与之联系起来。

我知道错误消息是有帮助的,但我真的不确定冲突是什么。而且我不确定这里还有哪些其他终身问题与我遇到的相同问题有关。

最佳答案

我们来看看Parser::next的签名:

fn next(&mut self) -> Option<&Token>

这个函数 promise 返回一个 Option<&Token> .有elided lifetimes这里;让我们重写签名以使其明确:

fn next<'b>(&'b mut self) -> Option<&'b Token<'b>>

我们现在可以看到 next在整个生命周期内都是通用的 'b .注意返回类型如何使用 'b , 不是 'a .这本身是有效的,因为编译器可以推断出 'b'a 短, 和可变引用 ( &'a mut T ) 是 covariant'a (在这种情况下,“协变”意味着我们可以用更短的生命周期代替生命周期 'a)。但是这个函数最终有希望的是结果至少和它自己一样长,而实际上它至少可以和 'a 一样长。 .

Parser::parse_row ,您正在尝试获取 Parser::next 的结果并将其插入 parent .我们来看看Parser::parse_row的签名:

fn parse_row(&mut self, parent: &mut Node)

我们在这里又遗漏了一些生命周期。让我们把它们拼出来:

fn parse_row<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>)

'c不会很重要,所以我们可以忽略它。

如果我们现在尝试编译,最后两个注释是不同的:

note: but, the lifetime must be valid for the lifetime 'd as defined on the method body at 88:5...
--> src/main.rs:88:5
|
88 | / fn parse_row<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>) {
89 | | loop {
90 | | match self.next() {
91 | | Some(ref token) => match token.state {
... |
99 | | }
100| | }
| |_____^
note: ...so that expression is assignable (expected Node<'d>, found Node<'_>)
--> src/main.rs:94:42
|
94 | parent.kids.push(Node::new_token(&token));
| ^^^^^^^^^^^^^^^^^^^^^^^

现在,其中一个匿名生命周期被标识为 'd .另一个仍然是匿名生命周期,这是编译器如何操纵生命周期的产物,但我们可以将其视为 'b。在这里。

问题现在应该更清楚了:我们正在尝试推送一个 Node<'b>进入 Node<'d> 的集合对象。类型必须是 Node<'d> 很重要,因为可变引用 ( &'a mut T ) 在 T 上是不变的(“不变”意味着它不能改变)。

让我们让生命周期匹配。首先,我们将更改 next的签名以匹配我们实际可以返回的内容:

fn next(&mut self) -> Option<&'a Token<'a>>

这意味着现在,当我们调用 self.next() 时在parse_row ,我们将能够构建一个 Node<'a> . Node<'x>只能存储Node<'x>对象(根据您对 Node 的定义),所以 parent参数的引用对象也必须是 Node<'a> 类型.

fn parse_row(&mut self, parent: &mut Node<'a>)

如果我们现在尝试编译,我们会在 Parser::parse_block 中得到一个错误正在调用 parse_row .问题类似于我们刚才看到的。 parse_block的签名是:

fn parse_block(&mut self, parent: &mut Node)

扩展为:

fn parse_block<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>)

这是编译器给出的这个详细签名的错误:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:78:26
|
78 | self.parse_row(&mut row);
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 72:1...
--> src/main.rs:72:1
|
72 | / impl<'a> Parser<'a> {
73 | | fn parse_block<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>) {
74 | | loop {
75 | | let mut row = Node::new(ParseState::Expr);
... |
112| | }
113| | }
| |_^
note: ...so that types are compatible (expected &mut Parser<'_>, found &mut Parser<'a>)
--> src/main.rs:78:26
|
78 | self.parse_row(&mut row);
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'd as defined on the method body at 73:5...
--> src/main.rs:73:5
|
73 | / fn parse_block<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>) {
74 | | loop {
75 | | let mut row = Node::new(ParseState::Expr);
76 | | match self.peek() {
... |
85 | | }
86 | | }
| |_____^
note: ...so that types are compatible (expected &mut Node<'_>, found &mut Node<'d>)
--> src/main.rs:84:20
|
84 | parent.push_if(row);
| ^^^^^^^

编译器无法推断 row 的类型(特别是其类型 Node<'x> 中的生命周期)。一方面,调用parse_row意味着它应该是Node<'a> , 但调用 push_if意味着它应该是Node<'d> . 'a'd是不相关的,所以编译器不知道如何统一它们。

解决方法很简单,和上面一样:只需要parent有类型 &mut Node<'a> .

fn parse_block(&mut self, parent: &mut Node<'a>)

现在您的代码可以编译了!

关于rust - 分配的匿名与结构生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47117797/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com