我想把两个闭包捆绑在一个结构中。一个闭包是用来测试输入是否有效的,另一个闭包是用来实际做这些事情的。下面是一个可行的变体:
struct Foo<T, F>
{
test: T,
func: F,
}
fn make_foo<A, B, T, F>(test: T, func: F) -> Foo<T, F>
where
T: Fn(A) -> bool,
F: Fn(A) -> B
{
Foo {
test,
func,
}
}
fn main() {
let foo = make_foo(|a: i32| {a > 5}, |a: i32| { a + 8 });
if (foo.test)(10) {
println!("{}", (foo.func)(10));
}
else {
println!("Input too small");
}
}
然而,Rust是Rust,有一些问题看起来不习惯。特别是,没有检查test
是否实际运行,也没有强制test
和func
使用相同的参数运行。
所以,我开始尝试修正这个问题。我的想法是foo.test
返回一个Option<Fn>
,其中Some
变量包含func
,但是我想使用的输入已经提供给它了。所以,作为初稿,类似于以下内容:
struct Foo<T>
{
test: T
}
fn make_foo<A, B, T, F, H>(t: T, f: F) -> Foo<H>
where
T: Fn(A) -> bool,
F: Fn(A) -> B,
H: Fn(A) -> Option<Fn() -> B>,
{
Foo {
test: |a: A| {
if t(a) {
Some(| | {f(a)})
}
else {
None
}
}
}
}
fn main() {
let foo = make_foo(|a: i32| {a > 5}, |a: i32| { a + 8 });
if let Some(f) = (foo.test)(10) {
println!("{}", f());
}
else {
println!("Input too small");
}
}
这说明Fn() -> B
需要dyn
,这当然也意味着它在编译时有未知的大小。所以我们Box
它:
fn make_foo<A, B, T, F, H>(t: T, f: F) -> Foo<H>
where
T: Fn(A) -> bool,
F: Fn(A) -> B,
H: Fn(A) -> Option<Box<dyn Fn() -> B>>,
{
Foo {
test: |a: A| {
if t(a) {
Some(Box::new(| | {f(a)}))
}
else {
None
}
}
}
}
现在它抱怨说它在我写的闭包上有expected type parameter
H , found closure
,我真的不知道这是什么意思。它还抱怨说它现在想在main
内部的foo
上有一个显式的类型签名,考虑到该类型包括闭包,我认为我甚至不能这样做。还有,我甚至还没有接触到a
参数。我可能需要一个move
。
我是不是在这里挖了一个无法脱身的洞,或者有什么像样的方法来解决这个问题,或者有什么更符合人体工程学的方法来解决我的代码运行中的两个问题?
1条答案
按热度按时间cs7cruho1#
可以使用existential type instead of an universal one:
一个类型参数总是意味着调用者可以为它选择一个类型,但是你不能提供一个任意的
Fn(A) -> Option<Box<dyn Fn() -> B>>
,你只能提供一个特定的值,你的闭包。