Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a struct callable?

Tags:

#![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.

like image 732
Андрей Ледовских Avatar asked Mar 17 '17 13:03

Андрей Ледовских


1 Answers

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:

  1. 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

  2. The implementation doesn't implement the supertrait FnMut, which itself requires the supertrait FnOnce. FnOnce is where the associated type Output is declared.

  3. The implementation neglects to define what concrete type Output should be.

  4. The implementation returns Self while the trait returns Self::Output.

  5. 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?
like image 188
Shepmaster Avatar answered Oct 06 '22 23:10

Shepmaster