rust - 如何正确解决结构中的生命周期推断?

标签 rust

rust playground code is here .
我有一个 Token 结构,它的生命周期为 'tok ,并且扫描仪的生命周期为 'lexer .我在另一个结构解析器中使用它们,然后我遇到了一个问题:

pub struct Token<'tok> {
    pub value: Cow<'tok, str>,
    pub line: usize,
}

pub struct Scanner {
    pub source: Vec<char>,
    pub current: usize,
    pub line: usize,
}

pub struct Parser<'lexer> {
    pub curr: &'lexer Token<'lexer>,
    pub prev: &'lexer Token<'lexer>,
    scanner: &'lexer mut Scanner,
}

impl <'lexer> Parser<'lexer> {
    pub fn advance(&mut self) {
        self.prev = self.curr;
        self.curr = &self.scanner.next(); // cannot inference lifetime
    }
}
我认为问题是 Token 有生命周期 'tok , 借用检查器不知道 'tok 之间的关系和 'lexer所以它不能推断出正确的生命周期。
但是,我可以通过将其修改为 the updated code 来避免该问题。 :
pub struct Parser<'lexer> {
    pub curr: Token<'lexer>,
    pub prev: Token<'lexer>,
    scanner: &'lexer mut Scanner,
}

impl <'lexer> Parser<'lexer> {
    pub fn advance(&mut self) {
        let prev = std::mem::replace(&mut self.curr, self.scanner.next());
        self.prev = prev;
    }
}
并使用 next() 制作的 Token是静态的:
impl Scanner {
    pub fn next(&mut self) -> Token<'static> {
        Token {
            value: Cow::from(""),
            line: 0,
        }
    }
}
它确实可以编译,但我认为这并不理想,因为所有标记都从扫描仪克隆到解析器(它们不再是引用)并一直存在到解析器生命的尽头。所以内存使用量翻了一番。有没有更合适的方法来处理这个问题?

最佳答案

实际上,您的代码结构对于处理借用检查器并不理想,原因如下:

  • Token结构体应该被拥有,结构体本身不需要任何分配(因为 token 是拥有的,所以需要一些间接方法来允许上一个 <-> 下一个切换)
  • 没有ParserLexer应该拥有基础数据,因此很容易绑定(bind)适当的生命周期
  • 在我们的案例中 Vec<Char>不是一个友好的类型(我们不需要拥有数据,这将使编译器更难理解生命周期),相反我们将使用 &'str 但您可以使用&[字符])

  • 这是一个编译得很好的例子
    pub struct Token<'source> {
        pub value: Cow<'source, str>,
        pub line: usize,
    }
    
    pub struct Scanner<'source> {
        pub source: &'source str,
        pub current: usize,
        pub line: usize,
    }
    
    pub struct Parser<'source> {
        pub curr: Option<Token<'source>>,
        pub prev: Option<Token<'source>>,
        scanner: Scanner<'source>,
    }
    impl <'source>Scanner<'source> {
        pub fn next(&'source /* DONT Forget to bound 'source to `self` */ self) -> Token<'source> {
            Token {
                value: Cow::from(self.source), /* `self.source` is bound to `'source` so the compiler understand that the token lifetime is the same than the source's one */
                line: 0,
            }
        }
    }
    
    impl <'lexer> Parser<'lexer> {
        pub fn advance(&'lexer mut self) {
            self.prev = self.curr.take();
            self.curr = Some(self.scanner.next());
        }
    }
    

    关于rust - 如何正确解决结构中的生命周期推断?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63397254/

    相关文章:

    rust - ErrorKind::__Noneexhaustive 的目的是什么?

    logging - 有没有办法在我的应用程序的生产构建中静态禁用 Rust 日志记录?

    generics - 有没有办法在 Rust 中模拟通用关联类型/关联类型构造函数?

    rust - 我怎样才能让编译器在我的包/文件中发出变量的生命周期?

    rust - 为什么具有未知标识符的匹配表达式会编译并运行?

    rust - 有没有办法为类似函数的 proc 宏提供通用参数?

    rust - 创建具有自定义错误类型的 super 服务

    rust - 为什么带有保护子句的匹配模式不是详尽无遗的?

    javascript - 如何使用wasm-bindgen调用先前定义的任意javascript函数Rust?

    closures - 有什么办法可以显式地写出闭包的类型吗?