【问题标题】:Is it possible to assign a closure to a variable of type impl Fn()?是否可以将闭包分配给 impl Fn() 类型的变量?
【发布时间】:2019-01-19 18:08:38
【问题描述】:

我能够使这段代码工作:

fn twice<T: Clone>(fst: impl Fn(T), snd: impl Fn(T)) -> impl Fn(T) {
    move |t| {
        fst(t.clone());
        snd(t)
    }
}

但是,我想要的是这个(没有拳击):

fn sub<T: Clone>(mut fst: impl Fn(T), snd: impl Fn(T)) {
    fst = move |t: T| {
        fst(t.clone());
        snd(t)
    };
}

有没有一种方法可以让第二段代码在没有装箱、使用特征、类型转换或任何其他方法的情况下工作? Rust 抱怨类型不匹配。

【问题讨论】:

  • 起初您的方法是错误的,您将fst 移动到sub 函数中,然后尝试更改它的值。但什么都不返回? fst 将被放入子函数中。

标签: types rust closures


【解决方案1】:

没有拳击就无法做到这一点。原因是输入中fst 的实际类型与您稍后覆盖它的闭包类型不同。使它们具有相同类型的唯一方法是使用 trait 对象。

盒装版本可能如下所示:

use std::mem;

fn sub<'a, T: Clone + 'a>(fst: &mut Box<dyn Fn(T) + 'a>, snd: impl Fn(T) + 'a) {
    // Replace the original fst with a dummy closure while the new closure is being
    // constructed, to avoid the reference being temporarily invalid
    let fst_orig = mem::replace(fst, Box::new(|_| {}));
    *fst = Box::new(move |t: T| {
        fst_orig(t.clone());
        snd(t)
    });
}


fn main() {
    let mut f1: Box<dyn Fn(i32)> = Box::new(|x| println!("f1: {}", x));
    let f2 = |x| println!("f2: {}", x);

    sub(&mut f1, f2);

    f1(42);
}

但我真的不知道你为什么要这样做!

【讨论】:

  • 还有这个简单的code,检查错误,它说:“注意:没有两个闭包,即使相同,也有相同的类型”,“帮助:考虑装箱你的闭包和/或将其用作特征对象”
  • 但我真的不知道你为什么要这样做! - 这 100%。只需reassign fst and let it get a new type
  • @Shepmaster 我实际上假设 OP 想要覆盖输入 fn 指针,这在问题中并没有完全表达。这就是为什么我包含一个使用该解决方案的示例main。如果只是重用函数 inside 的变量名,这似乎是一个微不足道的请求 - 但也许这就是 OP 真正想要的?
【解决方案2】:

回答您提出的问题,不,您还不能将闭包分配给impl Fn 类型的变量,因为您还不能声明这样的变量:

fn foo() {
    let x: impl Fn() = move || println!("Hello");
}
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
 --> src/lib.rs:2:12
  |
2 |     let x: impl Fn() = move || println!("Hello");
  |            ^^^^^^^^^

“但是等等!”你说,“我的函数参数中有这样的类型!”。事实是,不,你没有。

这个语法:

fn foo(x: impl Fn()) {}

只是这个的简写:

fn foo<F>(x: F)
where
    F: Fn(),
{}

您只是构建了一个泛型并应用了一个绑定到它的特征。

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-22
    • 2022-06-11
    相关资源
    最近更新 更多