How do I make a struct callable?

喜欢而已 提交于 2019-12-01 14:24:47

问题


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


回答1:


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?


来源:https://stackoverflow.com/questions/42859330/how-do-i-make-a-struct-callable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!