&str 字符串和生命周期

wir*_*bel 5 rust

我正在 Rust 中开发一个小型词法分析器。我的想法是将词法分析阶段放入Iterator特征的实现中。

struct Lexer {
    text: String
}

impl Iterator for Lexer {
    ...
    fn next(&mut self) -> Option<LexItem>{
        ....
        // slicing issue
        self.text = self.text[i .. self.text.len()]

    }
}
Run Code Online (Sandbox Code Playgroud)

我还没有完全理解这里的终身管理。我可以通过为属性定义具有生命周期的结构来解决问题text,这(可能)会使子切片变得更容易。然而我未能将这样的生命周期纳入我的代码中。另一方面,我很难将切片转换self.text[i .. .....]String再次(不知道是否可能)。

我尝试过的:

我尝试了以下修改:

struct Lexer<'a> {
    text: &'a str
}

impl<'a> Iterator for Lexer<'a> {
    ...
    fn next(&'a mut self) -> Option<LexItem>{
        ....
        // slicing issue
        self.text = self.text[i .. self.text.len()]

    }
}
Run Code Online (Sandbox Code Playgroud)

我收到错误:

src/lexer.rs:64:5: 81:6 错误:方法 `next` 具有不兼容的特征类型:预期绑定生命周期参数,找到具体生命周期 [E0053]

我尝试过的另一个实现

impl<'a> Iterator for Lexer<'a> {
    ...
    fn next<'b>(&'b mut self) -> Option<LexItem>{
        ....
        // slicing issue
        self.text = self.text[i .. self.text.len()]

    }
}
Run Code Online (Sandbox Code Playgroud)
src/lexer.rs:66:21: 66:52 错误:类型不匹配:
 预期为“&'a str”,
    找到了“str”
(预期 &-ptr,
    找到 str) [E0308]
src/lexer.rs:66 self.text = self.text[i .. self.text.len()];
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我认为这样的东西应该可以工作,因为我只会使用子切片。

Chr*_*gan 5

(顺便说一句:foo[i..foo.len()]应该始终等于foo[i..]。)

如果的类型是或 ,则self.text[i..]的类型是未调整大小的类型。为了使其大小合适(因此,为了使其工作),您需要将其转换为与 相同的类型。strself.textString&strtext

如果text是,则可以通过调用切片结果String来完成;.to_string()将自动获取参考,使其合法。因此,self.text = self.text[i..].to_string();。(std::borrow::ToOwned::to_owned也可以使用并且效率会稍微高一些。)

如果text&str,只需在切片操作前加上 前缀&,使其根据需要引用:self.text = &self.text[i..];

对于整个一生的问题,请阅读我对/sf/answers/1720291401/的回答;它解释了你的问题等等fn next(&'a mut self)

在我看来,您希望整个事情基于字符串切片(&str)而不是拥有的字符串(String)。前者适用于迭代器(请参阅上述答案),而后者则不适用于迭代器。

  • `.to_string()` 使用 `std::fmt` 基础设施,该基础设施相对较重。在像字符串这样的简单情况下,它现在应该在运行时完全优化(当我写答案时,这不是*完全*正确的),但是您可以形成某些细微的变体,这些变体不会完美地优化,而且仍然存在也有一点编译时开销。我自己现在可能最常写“String::from(text)”,但我不会对“text.to_string()”眨眼。 (2认同)