分配的匿名vs结构生命周期

时间:2017-11-05 03:11:27

标签: rust

对于这段代码(修剪一些,抱歉不多),我遇到了终身问题:

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));
   |                                          ^^^^^^^^^^^^^^^^^^^^^^^

所有参考文献都应该与相同的外部生命周期联系在一起。在我的完整代码中(我只是在这里有一段摘录),我希望能够抓住原始解析的源代码,并且我试图将所有内容与之结合起来。

我知道错误消息试图提供帮助,但我真的不确定冲突是什么。而且我不确定这里的其他终身问题与我有没有相同的问题有关。

1 个答案:

答案 0 :(得分:2)

让我们看一下Parser::next的签名:

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

此函数承诺返回Option<&Token>。这里有elided lifetimes;让我们重写签名,使其明确:

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

我们现在可以看到next在生命周期'b内是通用的。请注意返回类型如何使用'b,而不是'a。这本身就是有效的,因为编译器可以推断出'b'a更短,而可变引用(&'a mut T)比'acovariant( &#34;协变&#34;在此上下文中意味着我们可以用更短的生命周期代替生命期'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上不变(&#34;不变&#34;意味着它可以&#39;}改变)。

让生命与时俱进。首先,我们会更改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>)

现在你的代码编译了!