代码之家  ›  专栏  ›  技术社区  ›  jonny

无法引用&str的某个片段,因为它的寿命不够长,即使它引用的内容有效

  •  3
  • jonny  · 技术社区  · 6 年前

    scan 方法 Scanner struct将字符串片段作为源代码,将该字符串拆分为 Vec<&str> unicode_segmentation ),然后将每个字符委托给 scan_token 方法,该方法确定其词法标记并返回它。

    extern crate unicode_segmentation;
    use unicode_segmentation::UnicodeSegmentation;
    
    struct Scanner {
        start: usize,
        current: usize,
    }
    
    #[derive(Debug)]
    struct Token<'src> {
        lexeme: &'src [&'src str],
    }
    
    impl Scanner {
        pub fn scan<'src>(&mut self, source: &'src str) -> Vec<Token<'src>> {
            let mut offset = 0;
            let mut tokens = Vec::new();
            // break up the code into UTF8 graphemes
            let chars: Vec<&str> = source.graphemes(true).collect();
            while let Some(_) = chars.get(offset) {
                // determine which token this grapheme represents
                let token = self.scan_token(&chars);
                // push it to the tokens array
                tokens.push(token);
                offset += 1;
            }
            tokens
        }
    
        pub fn scan_token<'src>(&mut self, chars: &'src [&'src str]) -> Token<'src> {
            // get this lexeme as some slice of the slice of chars
            let lexeme = &chars[self.start..self.current];
            let token = Token { lexeme };
            token
        }
    }
    
    fn main() {
        let mut scanner = Scanner {
            start: 0,
            current: 0,
        };
        let tokens = scanner.scan("abcd");
        println!("{:?}", tokens);
    }
    

    error[E0597]: `chars` does not live long enough
      --> src/main.rs:22:42
       |
    22 |             let token = self.scan_token(&chars);
       |                                          ^^^^^ borrowed value does not live long enough
    ...
    28 |     }
       |     - borrowed value only lives until here
       |
    note: borrowed value must be valid for the lifetime 'src as defined on the method body at 15:17...
      --> src/main.rs:15:17
       |
    15 |     pub fn scan<'src>(&mut self, source: &'src str) -> Vec<Token<'src>> {
       |                 ^^^^
    

    我想我理解了为什么这不起作用的逻辑:错误表明 chars 需要和生命一样长寿 'src ,因为 tokens 查尔斯

    查尔斯 一生 (即 source )为什么不能呢 代币 之后参考此数据 已经放弃了吗?我对低级编程还相当陌生,我想我关于引用+生命周期的直觉可能有点被打破了。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Shepmaster Tim Diekmann    6 年前

    您的问题可以归结为:

    pub fn scan<'a>(source: &'a str) -> Option<&'a str> {
        let chars: Vec<&str> = source.split("").collect();
        scan_token(&chars)
    }
    
    pub fn scan_token<'a>(chars: &'a [&'a str]) -> Option<&'a str> {
        chars.last().cloned()
    }
    
    error[E0597]: `chars` does not live long enough
     --> src/lib.rs:3:17
      |
    3 |     scan_token(&chars)
      |                 ^^^^^ borrowed value does not live long enough
    4 | }
      | - borrowed value only lives until here
      |
    note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:13...
     --> src/lib.rs:1:13
      |
    1 | pub fn scan<'a>(source: &'a str) -> Option<&'a str> {
      |             ^^
    

    这个 scan_token 寿命: &'a [&'a str] . 自从 Vec 生命周期更短,这就是统一的生命周期。但是,向量的生存期不足以返回值。

    pub fn scan_token<'a>(chars: &[&'a str]) -> Option<&'a str>
    

    将这些更改应用到完整的代码中,您可以看到核心问题在 Token

    struct Token<'src> {
        lexeme: &'src [&'src str],
    }
    

    这种构造使您的代码绝对不可能编译,因为没有片的向量能够像片一样存在。您的代码在这种形式下是不可能的。

    能够 将可变引用传递给 Vec

    impl Scanner {
        pub fn scan<'src>(&mut self, source: &'src str, chars: &'src mut Vec<&'src str>) -> Vec<Token<'src>> {
            // ...
            chars.extend(source.graphemes(true));
            // ...
            while let Some(_) = chars.get(offset) {
                // ...
                let token = self.scan_token(chars);
                // ...
            }
            // ...
        }
    
        // ...    
    }
    
    fn main() {
        // ...
        let mut chars = Vec::new();
        let tokens = scanner.scan("abcd", &mut chars);
        // ...
    }
    

    你可能只是想 代币 成为 Vec<&'src str>

    另见: