#![feature(unboxed_closures)] #![feature(fn_traits)] struct foo; impl std::ops::Add for foo { type Output = foo; fn add(self, x: foo) -> foo { println!("Add for foo"); x } } impl Fn for foo { extern "rust-call" fn call(&self) -> Self { println!("Call for Foo "); self } } fn main() { let x = foo; let y = foo; x + y; x(); }
I implemented the Add
trait, but I don't understand how to call the struct as a function. I get the error:
error[E0243]: wrong number of type arguments: expected 1, found 0 --> src/main.rs:14:10 | 14 | impl Fn for foo { | ^^ expected 1 type argument
I'm new to Rust, and can't find examples how to make this thing happen.
You cannot yet implement the Fn*
traits in stable Rust. This is only possible with the nightly compiler using #[feature]
!
It's very useful to fully read the trait that you are implementing to see how to implement it. The Fn
trait is defined as:
pub trait Fn<Args>: FnMut<Args> { extern "rust-call" fn call(&self, args: Args) -> Self::Output; }
Notice any differences between the implementation and the definition? I see many:
The implementation doesn't provide a value for Args
! That's what the compiler is pointing at. See also Wrong number of type arguments: expected 1 but found 0
The implementation doesn't implement the supertrait FnMut
, which itself requires the supertrait FnOnce
. FnOnce
is where the associated type Output
is declared.
The implementation neglects to define what concrete type Output
should be.
The implementation returns Self
while the trait returns Self::Output
.
The implementation doesn't accept the second argument to call
. This argument contains any arguments passed in.
Additionally, types in Rust use PascalCase
, not snake_case
, so it should be Foo
.
#![feature(unboxed_closures)] #![feature(fn_traits)] struct Foo; impl Fn<()> for Foo { extern "rust-call" fn call(&self, _args: ()) { println!("Call (Fn) for Foo"); } } impl FnMut<()> for Foo { extern "rust-call" fn call_mut(&mut self, _args: ()) { println!("Call (FnMut) for Foo"); } } impl FnOnce<()> for Foo { type Output = (); extern "rust-call" fn call_once(self, _args: ()) { println!("Call (FnOnce) for Foo"); } } fn main() { let x = Foo; x(); }
Normally though, only one trait's implementation would have interesting code in it and the other trait implementations would delegate to it:
extern "rust-call" fn call(&self, args: ()) { println!("Foo called, took args: {:?}", args); } // ... extern "rust-call" fn call_mut(&mut self, args: ()) { self.call(args) } // ... extern "rust-call" fn call_once(self, args: ()) { self.call(args) }
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With