Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing traits for fn type

I want to implement custom trait for several concrete functions, i.e.

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.

like image 213
Slava Baginov Avatar asked Mar 11 '26 01:03

Slava Baginov


1 Answers

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.

like image 187
oli_obk Avatar answered Mar 12 '26 15:03

oli_obk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!