闭包中引用的生命周期

时间:2017-03-12 12:51:09

标签: rust

我需要一个闭包来引用其封闭环境中对象的某些部分。该对象是在环境中创建的,并且作用于它,但是一旦创建它就可以安全地移动到闭包。

用例是一个执行一些准备工作的函数,并返回一个将完成其余工作的闭包。这种设计的原因是执行约束:工作的第一部分涉及分配,其余部分必须不进行分配。这是一个最小的例子:

fn stage_action() -> Box<Fn() -> ()> {
    // split a freshly allocated string into pieces
    let string = String::from("a:b:c");
    let substrings = vec![&string[0..1], &string[2..3], &string[4..5]];

    // the returned closure refers to the subtrings vector of
    // slices without any further allocation or modification
    Box::new(move || {
        for sub in substrings.iter() {
            println!("{}", sub);
        }
    })
}

fn main() {
    let action = stage_action();
    // ...executed some time later:
    action();
}

这无法编译,正确地说明&string[0..1]和其他人不得超过string。但如果将string移入闭包中,则没有问题。有没有办法强制这种情况发生,或者另一种允许闭包引用在其外部创建的对象部分的方法?

我还尝试创建一个具有相同功能的struct,以使移动完全明确,但doesn't compile either。同样,编译失败,错误&later[0..1]和其他只存在直到函数结束的错误,但“借用的值必须对静态生命周期有效”。

即使completely avoiding a Box似乎没有帮助 - 编译器抱怨对象的活动时间不够长。

1 个答案:

答案 0 :(得分:2)

这里的封闭没有什么特别之处;它相当于:

fn main() {
    let string = String::from("a:b:c");
    let substrings = vec![&string[0..1], &string[2..3], &string[4..5]];
    let string = string;
}

您正在尝试移动 String,而有明显的借款。在我的例子中,它是另一个变量;在你的例子中它是关闭的环境。无论哪种方式,你仍然在移动它。

此外,您正在尝试将子字符串移动到与拥有字符串相同的闭包环境中。这会使整个问题等同于Why can't I store a value and a reference to that value in the same struct?

struct Environment<'a> {
    string: String,
    substrings: Vec<&'a str>,
}

fn thing<'a>() -> Environment<'a> {
    let string = String::from("a:b:c");
    let substrings = vec![&string[0..1], &string[2..3], &string[4..5]];
    Environment {
        string: string,
        substrings: substrings,
    }
}

fn main() {}
  

该对象是在环境中创建的,并且作用域为

我不同意; stringsubstrings在封闭环境的外部创建,移入其中。这就是让你绊倒的举动。

  

一旦创建,它就可以安全地移动到闭包。

这个的情况下,这是真的,但只是因为你,程序员,可以保证里面的字符串数据的地址 {{1}将保持不变。你知道这有两个原因:

  • String在内部使用堆分配实现,因此移动String不会移动字符串数据。
  • String永远不会发生变异,这可能导致字符串重新分配,使任何引用无效。

您的示例的最简单的解决方案是将切片简单地转换为String并让闭包完全拥有它们。如果这意味着你可以释放一个大字符串而不是一些较小的字符串,那么这甚至可能是一个净收益。

否则,您符合&#34下规定的标准;有一种特殊情况,即终身追踪过于热心&#34;在Why can't I store a value and a reference to that value in the same struct?中,您可以使用owning_ref

String

请注意,我不是owning_ref的专家用户,因此这可能不是最佳使用它。