簡體   English   中英

匿名與結構生存期的分配

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM