是否可以在不同的结构中存储包含闭包的 Rust 结构? [英] Is it possible to store a Rust struct containing a closure in a different struct?
问题描述
Crius 库提供Rust 的类似断路器的功能.Crius 定义了一个名为 Command
看起来像这样:
The Crius library provides
circuit-breaker-like functionality for Rust. Crius defines a struct called Command
which looks like this:
pub struct Command<P, T, CMD>
where
T: Send,
CMD: Fn(P) -> Result<T, Box<CommandError>> + Sync + Send,
{
pub config: Option<Config>,
pub cmd: CMD,
phantom_data: PhantomData<P>,
}
是否可以将 Command
的实例存储为不同结构中的字段?
Is it possible to store an instance of Command
as a field in a different struct?
我开始尝试从一个功能.简单地实例化类型是没有问题的:
I started out trying to return a value of this type from a function. Simply instantiating the type is no problem:
/// This function constructs a simple instance of `Command<P, T, CMD>` with the
/// types set to:
///
/// P ~ u8
/// T ~ u8
/// CMD: Fn(u8) -> Result<u8, Box<CommandError>> + Send + Sync
///
/// This function compiles fine. However, there is no *concrete* type
/// for `CMD`. In compiler output it will be referred to as an
/// "anonymous" type looking like this:
///
/// Command<u8, u8, [closure@src/lib.rs:19:21: 19:38]>
fn simple_command_instance() {
let _ = Command::define(|n: u8| Ok(n * 2));
}
为返回类型编写返回类型变得更加困难功能:
It becomes more difficult when writing a return type for the function:
fn return_command_instance() -> Command<u8, u8, ???> {
^
|
What goes here? -------
Command::define(|n: u8| Ok(n * 2))
}
编译器推断的类型是匿名的——不能放入那里.很多时候,当关闭被传递时,人们诉诸于使用 Box
,但是没有实现impl Fn
- 所以装箱类型打破crius::command::Command
给出的约束.
The type inferred by the compiler is anonymous - it can't be put in
there. Many times when closures are passed around, people resort to
using a Box<F: Fn<...>>
, however there is no implementation for
impl Fn<T> for Box<Fn<T>>
- so boxing the type breaks the
constraints given by crius::command::Command
.
在具有新 impl Trait
功能的 Rust 版本中(例如即将发布的稳定版本),这是可能的:
In versions of Rust that have the new impl Trait
feature (such as the
upcoming stable release), this is possible:
/// Use new `impl Trait` syntax as a type parameter in the return
/// type:
fn impl_trait_type_param() -> Command<u8, u8, impl Fn(u8) -> Result<u8, Box<CommandError>>> {
Command::define(|n: u8| Ok(n * 2))
}
这在稳定的 Rust 中不起作用,并且 impl Trait
只能用于返回类型,而不是结构成员.
This does not work in stable Rust and impl Trait
can only
be used in return types, not in struct members.
试图传播泛型类型最终看起来像这个:
Trying to propagate the generic type ends up looking something like this:
fn return_cmd_struct<F>() -> Command<u8, u8, F>
where
F: Fn(u8) -> Result<u8, Box<CommandError>> + Send + Sync,
{
Command::define(|n: u8| Ok(n * 2))
}
但这不会编译:
error[E0308]: mismatched types
--> src/lib.rs:33:21
|
33 | Command::define(|n: u8| Ok(n * 2))
| ^^^^^^^^^^^^^^^^^ expected type parameter, found closure
|
= note: expected type `F`
found type `[closure@src/lib.rs:33:21: 33:38]`
同样,我不知道有什么方法可以在结果签名.
Again, I don't know of a way to specify that concrete type in the result signature.
即使将类型作为泛型参数传播有效,它也会对于我们的特定用例仍然是一个问题.我们要存储一个Command
作为 actix 参与者的一部分,注册为SystemService
,需要一个 Default
实现,它再次最终迫使我们提供一个具体的类型.
Even if propagating the type as a generic parameter worked, it would
still be an issue for our specific use-case. We want to store a
Command
as part of an actix actor which registers as a
SystemService
, which requires a Default
implementation, which
again eventually forces us to provide a concrete type.
如果有人对可能的方法有任何想法,请分享他们.肯定知道它不可能也会很好.
If anyone has any ideas about possible ways to do this, please share them. Definitely knowing that it isn't possible would also be nice.
推荐答案
我目前不知道除了使用 impl
或 Box 之外,没有其他方法可以将闭包用作返回类型的一部分
,你已经提到了,在这种情况下不能使用.
I currently know of no way a closure may be used as part of a return type other than using impl
or Box
, both of which you have mentioned and cannot be used in this situation.
另一种方法是使用函数指针而不是闭包,如下所示:
An alternative would be to use a function pointer instead of a closure, like so:
fn return_command_instance() -> Command<u8, u8, fn(u8) -> Result<u8, Box<CommandError>>> {
Command::define(|n: u8| Ok(n * 2))
}
注意小写的 fn
表示函数指针而不是特征 Fn
.这在 高级功能&关闭.
Notice the lower case fn
to signify a function pointer and not the trait Fn
. This is explained in more details in the chapter on Advanced Functions & Closures.
这只有在你没有在函数中捕获任何变量时才有效,如果你这样做,它会被编译成一个闭包.
This will only work if you do not capture any variables in the function, if you do it will be compiled into a closure.
这篇关于是否可以在不同的结构中存储包含闭包的 Rust 结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!