我试图在一段使用回调的代码中实现clone_into_box模式,但遇到了一个我无法理解的错误。
基本上,我克隆了一个lambda的参数,但是借位检查器仍然抱怨我泄漏了对所述参数的引用。
我的问题:这是否是一个过度保守的借位检查器的例子(如果是这样,我如何以一种与借位检查器很好地配合的方式重写它),或者我在这里遗漏了什么,尽管克隆了,但确实泄漏了一个引用?
编码:
pub trait CloneIntoBox{
fn clone_into_box<'a>(&self) -> Box<dyn CloneIntoBox + 'a>;
}
impl<'a> Clone for Box<dyn CloneIntoBox + 'a> {
fn clone(&self) -> Self {
self.as_ref().clone_into_box()
}
}
# [derive(Clone)]
pub struct StructWithBox<'a> {
pub my_box: Box<dyn CloneIntoBox + 'a>,
}
# [derive(Clone)]
struct StructThatCanBeClonedIntoBox {
pub data: u32,
}
impl CloneIntoBox for StructThatCanBeClonedIntoBox {
fn clone_into_box<'a>(&self) -> Box<dyn CloneIntoBox + 'a> {
Box::new(self.clone())
}
}
pub type WalkCallback<'a> = dyn FnMut(&StructWithBox) + 'a;
pub fn walk(data: Vec<u32>, cb: &mut WalkCallback) {
for d in data{
let instance = StructWithBox{my_box: Box::new(StructThatCanBeClonedIntoBox{data:d})};
cb(&instance);
}
}
fn main() {
let data = vec![1, 2];
let mut result = vec![];
walk(data, &mut|param| result.push((*param).clone()));
}
Playground link(https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=80768178088472499d13667f577b5ec2)
提供:
error[E0521]: borrowed data escapes outside of closure
--> src/main.rs:39:28
|
38 | let mut result = vec![];
| ---------- `result` declared here, outside of the closure body
39 | walk(data, &mut|param| result.push((*param).clone()));
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `param` escapes the closure body here
| |
| `param` is a reference that is only valid in the closure body
2条答案
按热度按时间pxyaymoc1#
问题出在
StructWithBox
中的'a
。请考虑以下walk()
的实现:我还没有找到一种方法来使这实际上是不健全的:从
impl CloneIntoBox for &u32
返回的唯一内容是'static
引用,因为'a
是由调用者决定的。但是借位检查器并不知道:它假设'a
可以是回调中的任何生存期,然后我们将它推送到回调外的向量中,但它可以在回调完成后被释放。要解决此问题,可以在回调中使
'a
始终为'static
:或者干脆摆脱终生:
xdnvmnnf2#
等价于
这要求回调函数能够接受任何生存期的
StructWithBox
,只要它在回调函数被调用时是活动的。由于StructWithBox
的有效期可能不会超过这个时间,因此它不能被推送到生存期比回调函数更长的向量。将此更改为
允许回调只接受长于
'b
的生存期。在这种情况下,'b
被推断为与result
的生存期一样长,因此可以将StructWithBox<'b>
推送到result
。