我有一个接口(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/