rust - 创建一个实现特定 Fn 接口(interface)的结构

标签 rust traits rust-cargo

我有一个接口(interface),我想让它像函数一样可调用。我不需要像 Fn 特征那样在 Args 和 Output 上对其进行模板化,因为我想定义 args 和返回类型将是什么类型。当我尝试这样做时,我的代码无法编译:

#![allow(unused)]
#![feature(unboxed_closures, fn_traits)]

type ActionArgs = (i32, bool);

pub trait Action: Fn(ActionArgs) -> bool {
    extern "rust-call" fn call(&self, args: ActionArgs) -> bool;
}

struct Concrete {}

impl Action for Concrete {
    extern "rust-call" fn call(&self, args: ActionArgs) -> bool {
        args.0  == 2 && args.1
    }
}

fn main() {
    let c = Concrete{};
    c((2, true));
}
这导致(在带有夜间编译器的 rust 操场上):
error[E0277]: expected a `Fn<((i32, bool),)>` closure, found `Concrete`
  --> src/main.rs:12:6
   |
6  | pub trait Action: Fn(ActionArgs) -> bool {
   |                   ---------------------- required by this bound in `Action`
...
12 | impl Action for Concrete {
   |      ^^^^^^ expected an `Fn<((i32, bool),)>` closure, found `Concrete`
   |
   = help: the trait `Fn<((i32, bool),)>` is not implemented for `Concrete`

error: aborting due to previous error
我曾尝试关注其他问题,例如 this ,但没有成功。

最佳答案

看来您误解了 trait Trait: OtherTrait句法。这并不意味着“特质扩展了其他特质”。它的意思是“Trait 需要 OtherTrait 来实现”。
所以,这一行:

pub trait Action: Fn(ActionArgs) -> bool {
    //...
}
基本上意味着:“对于实现 Action 的每种类型,编译器,请检查它是否也会实现 Fn(ActionArgs) -> bool ”。就是这样——只有支票。
此外,要将某物用作函数,您必须至少实现 FnOnce - 否则函数调用语法将根本不可用。使用任何其他特征都无法做到这一点,因为 Fn*特征是所谓的语言项 - 这基本上意味着它们从编译器得到特殊处理,特别是通过允许其他无法访问的语法元素。
所以,在这里你唯一能做的就是从 Action 切换。使用 Fn*直接特征 - 可能离开 Action作为一种无方法的标记特征,如下所示:
#![allow(unused)]
#![feature(unboxed_closures, fn_traits)]

type ActionArgs = (i32, bool);

// Since we can't deconstruct the tuple in "sugary" syntax,
// we have to fall back to ordinary generics to use ActionArgs.
pub trait Action: Fn<ActionArgs, Output = bool> {}

struct Concrete {}

// These two implementations delegate to the Fn one.
// Of course, they might also be completely separate, if you like.
impl FnOnce<ActionArgs> for Concrete {
    type Output = bool;
    extern "rust-call" fn call_once(self, args: ActionArgs) -> bool {
        self.call(args)
    }
}
impl FnMut<ActionArgs> for Concrete {
    extern "rust-call" fn call_mut(&mut self, args: ActionArgs) -> bool {
        self.call(args)
    }
}

// This implementation is what you used in Action before.
impl Fn<ActionArgs> for Concrete {
    extern "rust-call" fn call(&self, args: ActionArgs) -> bool {
        args.0  == 2 && args.1
    }
}

// Finally, this blanket implementation makes Action available
// on every function-like type with correct signature...
impl<T: Fn<ActionArgs, Output = bool>> Action for T {}
// ...so that we can use it as a trait bound, like here:
fn act(c: impl Action) {
    println!("{}", c(2, true));
}

fn main() {
    let c = Concrete{};
    act(c);
}
Playground

关于rust - 创建一个实现特定 Fn 接口(interface)的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64606885/

相关文章:

configuration - 您可以使用 Cargo 共享依赖树上的 `cfg!` 吗?

rust - 仅在必要时为交叉编译设置 cargo 链接器

scala - 可堆叠特征模式可以与单例对象一起使用吗?

closures - 在 Rust 中使用标准输入数据实例化结构

rust - 如何在通用结构中定义 const 闭包

rust - 借用检查器如何处理从函数返回的引用?

rust - 需要 Sized 的特征与无法拥有该特征的特征对象有什么关系?

javascript - ES 6 类 - Mixin

rust - 二进制操作 == 不能应用于类型 syn::Path

rust - 如果在Rust book 20.3中将发送Terminate消息和thread.join()放在一个循环中,为什​​么会出现死锁?