简体   繁体   中英

Implementing traits for fn type

I want to implement custom trait for several concrete functions, ie

trait ToTarget {
    fn custom_str(&self) -> String;
}

impl ToTarget for fn() -> String {
    fn custom_str(&self) -> String {
        self()
    }
}

impl ToTarget for fn(i32) -> String {
    fn custom_str(&self) -> String {
        self(4)
    }
}

fn a() -> String {
    "abc".to_string()
}

fn b(x: i32) -> String {
    x.to_string()
}

fn main() {
    println!("{}", b.custom_str());
}

However, this does not compile giving the next error:

<anon>:26:22: 26:34 error: no method named `custom_str` found for type `fn(i32) -> collections::string::String {b}` in the current scope
<anon>:26     println!("{}", b.custom_str());
                               ^~~~~~~~~~~~
note: in expansion of format_args!
<std macros>:2:25: 2:56 note: expansion site
<std macros>:1:1: 2:62 note: in expansion of print!
<std macros>:3:1: 3:54 note: expansion site
<std macros>:1:1: 3:58 note: in expansion of println!
<anon>:26:5: 26:36 note: expansion site
<anon>:26:22: 26:34 help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `custom_str`, perhaps you need to implement it:
<anon>:26:22: 26:34 help: candidate #1: `ToTarget`
error: aborting due to previous error
playpen: application terminated with error code 101

However, If I specify the type of b, code compiles:

println!("{}", (b as fn(i32) -> String).custom_str());

So the question is: is there a way to make my first version of code with

println!("{}", b.custom_str());

compile? Specifying type of function every time I want to use my trait is really annoying.

The problem is that every function has its very own type, but might have the same signature as another function. You implemented the trait ToTarget for all functions with the signature fn(i32) -> String .

As an example: your function b has type fn(i32) -> collections::string::String {b} (note the {b} in the type), but you cannot specify this type explicitly.

What you can do is implement ToTarget for all types that that implement Fn(i32) -> String :

trait ToTarget {
    fn custom_str(&self) -> String;
}

impl<T> ToTarget for T where T: Fn(i32) -> String {
    fn custom_str(&self) -> String {
        self(4)
    }
}

fn b(x: i32) -> String {
    x.to_string()
}

But then you cannot implement ToTarget for Fn() -> String or any other types for that matter, since there might be a type that implements Fn(i32) -> String AND Fn() -> String , which would yield two different implementations for the same type. As far as I can see, even impl specialization won't help here, so you are out of luck.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM