为什么克隆和/或复制的值会出现此引用错误?

问题描述 投票:0回答:2

我不知道是什么导致了这个引用错误:

error[E0515]: cannot return value referencing local variable `s1`
   --> src/regexp/mod.rs:538:9
    |
528 |             match s1.step() {
    |                   --------- `s1` is borrowed here
...
538 |         steps
    |         ^^^^^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `regexp` due to previous error

我已经制作了 CharsStep 结构克隆和复制,并且在两次推送中我都尝试了推送对象的克隆并进行分配以获取副本并推送它。我以为我正在理解内存模型,但是这个让我卡住了。这里借的是什么?在添加到步骤向量之前,不是所有的引用都被复制了(多次!)吗?

我查看了建议的参考,它只是解释了我所知道的,我只能返回值,而不是对本地值的引用,但由于它们是克隆的,我认为它们没问题。

pub trait Walker {}
    
// used to hold the state at each step in the search walk, and later to build the final result if successful
#[derive(Clone, Copy)]
struct CharsStep<'a> {
    node: &'a CharsNode,
    string: &'a str,
    matched: &'a str,
}

impl<'a> Walker for CharsStep<'a> {}

impl<'a> CharsStep<'a> {
    fn walk(node: &'a CharsNode, string: &'a str) -> Vec<Box<dyn Walker + 'a>> {
        let mut steps = Vec::<Box<dyn Walker>>::new();
        let mut step = CharsStep {
            node,
            string,
            matched: "",
        };
        if node.limit_desc.0 == 0 {
            steps.push(Box::new(step.clone()));
        }

        for i in 1..node.limit_desc.1 {
            let s1 = step;
            match s1.step() {
                Some(s) => {
                    if i >= node.limit_desc.0 {
                        steps.push(Box::new(s.clone()));
                    }
                    step = s.clone();
                }
                None => {
                    break;
                }
            }
        }
        steps
    }
    
    fn step(&self) -> Option<CharsStep> {
        let len = self.node.string.len();
        if self.string[0..len] == self.node.string {
            Some(CharsStep {
                node: self.node,
                string: &self.string[len..],
                matched: &self.string[..len],
            })
        } else {
            None
        }
    }
}
rust lifetime borrow-checker
2个回答
5
投票

我很惊讶没有关于这个的警告(甚至是 Clippy lint)。

你忘记了一个lifetime annotation,实质上改变了意思:

fn step(&self) -> Option<CharsStep> {

这被解释为好像你写了:

fn step<'s>(&'s self) -> Option<CharsStep<'s>> {

当您调用

step
时,会创建一个临时引用,因为
step
需要
&self
。由于缺少此生命周期注解,编译器说您正在借用当前函数拥有的数据是非常正确的。它只能看函数签名,这就是它所说的。

由于您实际上是在借用

self
本身借用的数据,因此您需要将生命周期更改为与那里引用的数据相同,即impl上下文中的
'a

fn step(&self) -> Option<CharsStep<'a>> {

1
投票
fn step(&self) -> Option<Self>

将步进函数签名更改为此将起作用。

错误是由这些行引起的

steps.push(Box::new(s.clone()));
step = s.clone();

如果您尝试删除它们,您的代码应该可以工作:)。但为什么会这样?

让我们看看

step
函数的函数签名。

fn step(&self) -> Option<CharsStep>

它引用 self 并返回一个拥有的值。编译器认为

CharStep
是由 step 函数生成的,但在内部它只是传递给它的任何内容的引用。 该值现在由
match
块拥有。当你将它推入向量时,它不会创建深度克隆,因为它有引用,这就是为什么编译器说 steps 拥有由 step 函数生成的该函数的数据。

正如@peter-hall 所建议的那样,更改 step 函数的签名以包括生命周期应该可行,因为编译器将知道它与 walk 函数的输入值具有相同的生命周期,并且即使在该函数退出后也将有效。

© www.soinside.com 2019 - 2024. All rights reserved.