我需要一个闭包来引用其封闭环境中的对象部分 . 该对象是在环境中创建的,并且作用于它,但是一旦创建它就可以安全地移动到闭包 .
用例是一个执行一些准备工作的函数,并返回一个将完成其余工作的闭包 . 这种设计的原因是执行约束:工作的第一部分涉及分配,其余部分必须不进行分配 . 这是一个最小的例子:
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]
和其他人只能活到函数结束,但"borrowed value must be valid for the static lifetime" .
即使completely avoiding a Box也没有足够长的时间 .
1 回答
这里的封闭没有什么特别之处;它相当于:
您正试图移动
String
,而有优秀的借款 . 在我的例子中,它是关闭环境的's to another variable; in your example it' . 无论哪种方式,你仍然在移动它 .此外,您正在尝试将子字符串移动到与拥有字符串相同的闭包环境中 . 这使整个问题等同于Why can't I store a value and a reference to that value in the same struct?:
我不同意;
string
和substrings
在闭包的环境之外创建并移入其中 . 它绊倒了你 .在这种情况下,这是真的,但这只是因为程序员可以保证
String
内的字符串数据的地址保持不变 . 你知道这有两个原因:String
在内部使用堆分配实现,因此移动String
不会移动字符串数据 .永远不会突变
String
,这可能导致字符串重新分配,使任何引用无效 .对于您的示例,最简单的解决方案是简单地将切片转换为
String
并让闭包完全拥有它们 . 如果这意味着你可以释放一个大字符串而不是一些较小的字符串,这甚至可能是一个净收益 .否则,您符合Why can't I store a value and a reference to that value in the same struct?中"There is a special case where the lifetime tracking is overzealous"下的标准,因此您可以使用owning_ref:
请注意,我不是owning_ref的专家用户,因此这可能不是最佳用途 .