&str、String和生命周期

5

我正在为Rust编写一个小型的词法分析器。我想把词法分析阶段放到Iterator trait的实现中。

struct Lexer {
    text: String
}

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

    }
}

我还没有完全理解这里的生命周期管理。如果为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()]

    }
}

我遇到了以下错误:

src/lexer.rs:64:5: 81:6 error: 方法 `next` 的 trait 类型不兼容: 预期绑定生命周期参数,发现具体的生命周期 [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()]

    }
}
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()];
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我认为这样的代码应该是可以工作的,因为我只使用子切片。

1个回答

5
(顺便说一下:foo[i..foo.len()]应始终等同于foo [i..] 。)
如果self.text的类型是String&str,那么self.text [i..]的类型是不定大小的类型str。为了使它具有大小(因此使其工作),您需要将其转换为与text相同的类型。
如果textString,则可以通过在切片结果上调用 .to_string()来完成此操作;将自动取用引用,使其合法。因此,self.text= self.text [i ..] .to_string(); 。(std::borrow::ToOwned ::to_owned 也可以使用,并且略微更有效率。)
如果text&str,则只需在切片操作前加上&即可,从而使其获取所需的引用: self.text = &self.text [i..];
对于整个生存期的问题,请阅读我对 https://dev59.com/ZWAf5IYBdhLWcg3wgy4Y#24575591 的回答;它解释了您对fn next(&'a mut self)等的问题。
在我看来,您想让整个程序都基于字符串切片(&str),而不是拥有的字符串(String)。前者适用于迭代器(请参见上述答案),而后者则不适用。

1
你提到了"“std::borrow::ToOwned::to_owned也可以使用,而且会稍微更有效率。” 你能详细解释一下为什么它会稍微更有效率吗?另一方面,在这种情况下,to_string()/to_owned()中哪一个更符合惯用法? - julen
2
.to_string() 使用相对较重的 std::fmt 基础设施。在像字符串这样的简单情况下,它现在应该会在运行时完全优化掉(当我写答案时这不是完全正确的),但是有一些轻微的变体你可以形成,它们无法完美地优化掉,并且仍然存在一些编译时开销。我自己现在可能最常写 String::from(text),但是我也不会对 text.to_string() 感到惊讶。 - Chris Morgan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接