【问题标题】:Rust calling trait alias for closureRust 为闭包调用 trait 别名
【发布时间】:2020-11-10 20:06:00
【问题描述】:

我正在使用 trait 为闭包创建别名,这样我就不必在整个代码中多次重复声明,但是我不知道如何将 trait 转换回 Fn 以便我可以调用它总的来说,这可能吗?

trait Closure: Send + Sync {}
impl <F: Send + Sync> Closure for F where F: Fn(&str) -> bool {}

pub struct Struct {
    pub closure: Box<dyn Closure>
}

impl Struct {
    pub fn new(closure: impl Closure + 'static) -> Self {
        Self{
            closure: Box::new(closure)
        }
    }
}

pub fn main() {
    let s = Struct::new(|f: &str| f.is_empty());

    let result: bool = (s.closure)("hello world"); //TODO
    println!("{}", result );
}

【问题讨论】:

  • 闭包会一直是Fn(&amp;str) -&gt; bool吗?
  • 是的,这个结构的参数和返回类型总是相同的

标签: rust


【解决方案1】:

您正在尝试调用 Box&lt;dyn Closure&gt; 作为方法。那时,编译器对这种类型的所有了解就是它实现了Closure。它不知道它是函数、结构还是其他任何东西,这就是您的代码无法编译的原因。

您可以通过向 Closure 特征添加关联方法来解决此问题。这是一种非常常见的函数建模方式:

pub trait Closure: Send + Sync {
    fn call(&self, input: &str) -> bool;
}

你可以为Fn类型实现它:

impl <F: Send + Sync> Closure for F where F: Fn(&str) -> bool {
    fn call(&self, input: &str) -> bool {
        self(input)
    }
}

并通过简单地调用 call 方法来调用 Closure 特征对象:

let s = Struct::new(|f: &str| f.is_empty());
let result: bool = s.closure.call("hello world");

【讨论】:

    【解决方案2】:

    正如 Ibraheem Ahmed 的回答所指出的,Closure 通常不保证任何实现它的类型都是函数。但是您可以通过添加 Fn 作为超特征来做到这一点:

    pub trait Closure: Send + Sync + Fn(&str) -> bool {}
    

    更改这一行后,您的代码将编译并运行。

    此选项与向特征添加显式 call 方法的其他选项之间的区别在这里,Closure 可以为闭包和函数指针实现 - 不适用于结构或枚举— 因为在稳定的 Rust(从 1.47.0 版开始)中,没有办法编写 impl Fn for MyType。但是,如果您只打算将此 trait 与 |f: &amp;str| f.is_empty() 这样的实际闭包一起使用,那没问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-25
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-27
      相关资源
      最近更新 更多