Rust自定义非泛型可调用Trait编译报错,求解决方法
问题分析
你遇到的错误根源在于,当你让Action trait继承Fn(ActionArgs) -> bool时,意味着任何实现Action的类型必须同时实现Fn<((i32, bool),)> trait。但你只给Concrete实现了Action的call方法,并没有满足Fn trait的要求——Rust的Fn系列trait是编译器特殊处理的,不能通过继承另一个trait的call方法自动实现。
解决方案
我们不需要让Action继承Fn,而是自定义独立的Action trait,然后为所有实现Action的类型自动实现Fn、FnMut、FnOnce这三个核心调用trait,这样就能让你的类型支持函数式调用语法。
以下是修正后的完整代码:
#![allow(unused)] #![feature(unboxed_closures, fn_traits)] type ActionArgs = (i32, bool); // 自定义Action trait,定义我们需要的调用逻辑 pub trait Action { fn call(&self, args: ActionArgs) -> bool; } // 为所有实现Action的类型实现Fn trait(支持不可变调用) impl<T: Action> Fn<(ActionArgs,)> for T { extern "rust-call" fn call(&self, args: (ActionArgs,)) -> bool { self.call(args.0) } } // 实现FnMut(支持可变调用,Fn继承自FnMut) impl<T: Action> FnMut<(ActionArgs,)> for T { extern "rust-call" fn call_mut(&mut self, args: (ActionArgs,)) -> bool { self.call(args.0) } } // 实现FnOnce(支持消耗式调用,FnMut继承自FnOnce) impl<T: Action> FnOnce<(ActionArgs,)> for T { type Output = bool; extern "rust-call" fn call_once(self, args: (ActionArgs,)) -> bool { self.call(args.0) } } struct Concrete {} impl Action for Concrete { fn call(&self, args: ActionArgs) -> bool { args.0 == 2 && args.1 } } fn main() { let c = Concrete{}; // 现在可以像函数一样调用了 assert!(c((2, true))); assert!(!c((1, true))); assert!(!c((2, false))); }
关键说明
- 分离自定义逻辑与标准调用trait:我们把业务逻辑放在
Action的call方法中,而标准的Fn系列trait只是转发调用到Action::call,这样既满足了自定义参数/返回值的需求,又兼容Rust的函数调用语法。 - 完整实现Fn系列trait:因为
Fn继承自FnMut,FnMut又继承自FnOnce,所以我们需要为这三个trait都提供实现,确保类型能在所有调用场景下正常工作(比如不可变借用、可变借用、消耗自身的调用)。 - 泛型实现减少重复代码:通过
impl<T: Action> Fn<...> for T的方式,所有实现Action的类型都会自动获得函数调用能力,不需要为每个类型单独实现Fn系列trait。
内容的提问来源于stack exchange,提问作者matanmarkind
相关产品推荐
相关产品推荐

