[英]Anonymous vs struct lifetime for assignment
对于此代码(修剪了一些,抱歉,不要再多了),我遇到了终身问题:
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)
}
}
( 游乐场 )
这是错误消息:
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));
| ^^^^^^^^^^^^^^^^^^^^^^^
所有参考都应绑定到相同的外部寿命。 在我的完整代码中(我只是在这里摘录了一部分),我希望可以使用原始的已解析源,并且我正在尝试将所有内容都与此相关。
我知道错误消息正在尝试提供帮助,但是我真的不确定冲突是什么。 我不确定这里还有哪些终身问题与我所遇到的同一问题有关。
让我们看一下Parser::next
的签名:
fn next(&mut self) -> Option<&Token>
该函数承诺返回Option<&Token>
。 这里有被遗忘的生命 。 让我们重写签名以使其明确:
fn next<'b>(&'b mut self) -> Option<&'b Token<'b>>
现在我们可以看到, next
在生命周期'b
是通用的。 注意返回类型如何使用'b
而不是'a
。 这本身是有效的,因为编译器可以推断出'b
比'a
a短,并且可变引用( &'a mut T
)与'a
(在这种情况下为“ covariant”)是协变的,这意味着我们可以替代寿命'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>>
这意味着现在,当我们在parse_row
调用self.next()
时,我们将能够构造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>)
现在您的代码可以编译了!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.