我想写一个FuncWrapper
结构体,其中包含一个new
函数,该函数以一个(Boxed)闭包作为参数,并返回一个装饰闭包,该闭包只是向传入闭包添加一些样板。但我也希望返回值是“owned”的,以允许以下情况(例如):
fn main() {
let a: FuncWrapper<u32>;
{
let foo = |x: u32| {print!("{}", x)};
let b = &Box::new(foo);
a = FuncWrapper::new(b);
}
let _c = (a.func)(42);
}
也就是说,我希望new的返回值是一个“owned”值。
现在我最近了解到Rust(Trais)中的所有闭包都必须有一个与它们相关联的生命周期(如果没有指定,它将默认为'static
)。但我认为,返回值new
的FuncWrapper中闭包的任何生命周期似乎都是错误的。
我不希望生存期是传入引用的生存期,因为这将太短。例如,下面的代码 * 不会 * 工作,因为返回值的生存期是参数f_box_ref
的生存期,在我提供的上述情况下,它的生存期不够长
struct FuncWrapper<'b, DomainType> {
func: Box<dyn Fn(DomainType) + 'b>
}
impl<'b, DomainType> FuncWrapper<'b, DomainType> {
fn new<F: Fn(DomainType) + 'static>(f_box_ref: &'b Box<F>) -> FuncWrapper<'b, DomainType> {
let new_f = move |a: DomainType| {
// ..add some boilerplate then
(**f_box_ref)(a)
};
let b = Box::new(new_f);
FuncWrapper {func: b}
}
}
导致
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:22:18
|
22 | let b = &Box::new(foo);
| ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
23 | a = FuncWrapper::new(b);
24 | }
| - temporary value is freed at the end of this statement
...
27 | }
| - borrow might be used here, when `a` is dropped and runs the destructor for type `FuncWrapper<'_, u32>`
|
= note: consider using a `let` binding to create a longer lived value
将返回参数的生存期改为'static
似乎也是错误的,因为我的目标是 * 在new
函数'* 中创建一个新闭包,(那么它怎么可能是静态的呢?)
struct FuncWrapper<DomainType> {
func: Box<dyn Fn(DomainType) + 'static>
}
impl<DomainType> FuncWrapper<DomainType> {
fn new<'b, F: Fn(DomainType) + 'static>(f_box_ref: &'b Box<F>) -> FuncWrapper<DomainType> {
let new_f = move |a: DomainType| {
// ..add some boilerplate then
(**f_box_ref)(a)
};
let b = Box::new(new_f);
FuncWrapper {func: b}
}
}
错误
error[E0759]: `f_box_ref` has lifetime `'b` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:7:21
|
6 | fn new<'b, F: Fn(DomainType) + 'static>(f_box_ref: &'b Box<F>) -> FuncWrapper<DomainType> {
| ---------- this data with lifetime `'b`...
7 | let new_f = move |a: DomainType| {
| _____________________^
8 | | // ..add some boilerplate then
9 | | (**f_box_ref)(a)
10 | | };
| |_________^ ...is used here...
11 | let b = Box::new(new_f);
12 | FuncWrapper {func: b}
| - ...and is required to live as long as `'static` here
这个错误让我很吃惊,因为我以为move
的任务是按值捕获,一开始我以为我需要先取消引用f_box_ref
,但是
impl<DomainType> FuncWrapper<DomainType> {
fn new<'b, F: Fn(DomainType) + 'static>(f_box_ref: &'b Box<F>) -> FuncWrapper<DomainType> {
let f_box: Box<F> = *f_box_ref;
let new_f = move |a: DomainType| {
// ..add some boilerplate then
(*f_box)(a)
};
let b = Box::new(new_f);
FuncWrapper {func: b}
}
}
导致
error[E0507]: cannot move out of `*f_box_ref` which is behind a shared reference
--> src/main.rs:7:30
|
7 | let f_box: Box<F> = *f_box_ref;
| ^^^^^^^^^^
| |
| move occurs because `*f_box_ref` has type `Box<F>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*f_box_ref`
唉,按照提示“帮助:考虑借用以下内容:&*f_box_ref
“也没有帮助
impl<DomainType> FuncWrapper<DomainType> {
fn new<'b, F: Fn(DomainType) + 'static>(f_box_ref: &'b Box<F>) -> FuncWrapper<DomainType> {
let f_box: &Box<F> = &*f_box_ref;
let new_f = move |a: DomainType| {
// ..add some boilerplate then
(*f_box)(a)
};
let b = Box::new(new_f);
FuncWrapper {func: b}
}
}
错误
error[E0759]: `f_box_ref` has lifetime `'b` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:7:31
|
6 | fn new<'b, F: Fn(DomainType) + 'static>(f_box_ref: &'b Box<F>) -> FuncWrapper<DomainType> {
| ---------- this data with lifetime `'b`...
7 | let f_box: &Box<F> = &*f_box_ref;
| ^^^^^^^^^^^ ...is used here...
...
13 | FuncWrapper {func: b}
| - ...and is required to live as long as `'static` here
所以很明显,我们仍然没有返回任何类似于新拥有的闭包的东西,并且对返回的闭包的生命周期的任何选择似乎都是武断和错误的。
我想做的事应该是很平常的事。我错过了什么?
2条答案
按热度按时间2ul0zpep1#
这是相当直接的,要从引用中获得一个拥有的类型,你有3个选项可以立即想到:
Copy
、Clone
或ToOwned
。ToOwned
更高级一点,因为它也可以更改类型,而且由于Copy
需要Cloned
,我将重点介绍后面的内容。要从
&Box<Fn>
获取拥有的Fn
,只需调用clone()
:hxzsmxv22#
因为它不是
FnMut
,而只是Fn
,也许您可以使用Rc
来代替Box
?您始终可以克隆Rc