[英]Is there no way to (one way or another) create an owned version of a (Box of) closure in rust?
I want to write a FuncWrapper
struct with a new
function that takes a (Boxed) closure as parameter, and returns a decorated closure that just adds some boilerplate to the incoming one.我想用一个new
的 function 编写一个FuncWrapper
结构,它将一个 (Boxed) 闭包作为参数,并返回一个装饰闭包,它只是向传入的闭包添加一些样板。 But I also want the returned value to be "owned", to allow for the following (eg):但我也希望返回值被“拥有”,以允许以下(例如):
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);
}
That is, I want for the return value of new to be an "owned" value.也就是说,我希望 new 的返回值是一个“拥有的”值。
Now I recently learned that all closures in Rust (being Trais) must have a lifetime associated with them (and it will default to 'static
if not specified.) But I suppose its seems that any lifetime for the closure in the FuncWrapper of the return value of new
will be wrong.现在我最近了解到 Rust 中的所有闭包(作为 Trais)必须具有与之相关联的生命周期(如果未指定,它将默认为'static
。)但我想它似乎是返回的 FuncWrapper 中闭包的任何生命周期new
的价值将是错误的。
I don't want the lifetime to be that of the incoming reference, because this will be too short.我不希望生命周期是传入引用的生命周期,因为这太短了。 Eg the following will not work because it the lifetime of the return value is that of the parameter f_box_ref
which does not live long enough in the case I provide above例如,以下将不起作用,因为返回值的生命周期是参数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}
}
}
results in结果是
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
Changing the lifetime of the return parameter to 'static
also seems wrong, since my goal is to create a new closure inside the new
function` , (so how could it be static?) but regardless this:将返回参数的生命周期更改为'static
似乎也是错误的,因为我的目标是在new
函数中创建一个新的闭包`,(所以它怎么可能是 static?)但无论如何:
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}
}
}
errors with错误与
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
The error surprised me since I thought the job of move
was to capture by value.这个错误让我感到惊讶,因为我认为move
的工作是按价值捕获。 At first I thought that I need to dereference the f_box_ref
first?起初我以为我需要先取消引用f_box_ref
? But that但是那个
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}
}
}
results in结果是
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`
Alas, following the hint to "help: consider borrowing here: &*f_box_ref
" doesn't help either las,按照“帮助:考虑在这里借用: &*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}
}
}
errors with错误与
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
so obviously we're still not returning anything like a new owned closure, and any choice for the lifetime of the returned closure seems arbitrary and wrong.所以很明显我们仍然没有返回任何类似新拥有的闭包的东西,并且对返回的闭包的生命周期的任何选择似乎都是武断和错误的。
What I'm trying to do here seems like it should be common.我在这里尝试做的事情似乎应该很普遍。 What am I missing?我错过了什么?
It's fairly straight forward, to get an owned type from a reference you have 3 options that come to mind immediately: Copy
, Clone
or ToOwned
.这非常简单,要从引用中获取拥有的类型,您会立即想到 3 个选项: Copy
、 Clone
或ToOwned
。 ToOwned
is a little more advanced since it can change the type as well and since Copy
requires Cloned
I'll focus on the later. ToOwned
稍微高级一点,因为它也可以更改类型,并且由于Copy
需要Cloned
,我将重点关注后者。
To get an owned Fn
from a &Box<Fn>
you can just call clone()
:要从&Box<Fn>
获取拥有的Fn
,您只需调用clone()
:
impl<DomainType> FuncWrapper<DomainType> {
fn new<F: Fn(DomainType) + Clone + 'static>(f_box_ref: &Box<F>) -> FuncWrapper<DomainType> {
let f_box = f_box_ref.clone();
let new_f = move |a: DomainType| {
// ..add some boilerplate then
(f_box)(a)
};
let b = Box::new(new_f);
FuncWrapper { func: b }
}
}
Since it is not FnMut
, just Fn
maybe you can use an Rc
instead of Box
?因为它不是FnMut
,只是Fn
也许你可以使用Rc
而不是Box
? You can always clone an Rc
你总是可以克隆一个Rc
use std::rc::Rc;
impl<DomainType> FuncWrapper<DomainType> {
fn new<F: Fn(DomainType) + 'static>(f_rc: Rc<F>) -> FuncWrapper<DomainType> {
let new_f = move |a: DomainType| {
// ..add some boilerplate then
(f_rc)(a)
};
let b = Box::new(new_f);
FuncWrapper { func: b }
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.