#![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:
- What is a crate attribute and where do I add it?