Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call static method from trait on generic type

I have a trait with one function that does not take self as an argument:

trait MyTrait {
    fn function(x: i32) -> i32;
}

struct Dummy;

impl MyTrait for Dummy {
    fn function(x: i32) -> i32 {
        x * 2
    }
}

fn call_method<T: MyTrait>(object: T) {
    let x = object.function(2);
}

fn main() {}

The user of the library is required to implement the trait for any type, usually an empty struct. One of my functions accepts a generic type that implements MyTrait. When I try to call the function method on the generic type, it gives me this error:

error: no method named function found for type T in the current scope

I tried the solution in the answer to this question, but I get the same error. How can I call a static method on a generic type?

like image 479
pengowen123 Avatar asked Dec 17 '15 07:12

pengowen123


2 Answers

When I try to call the function method on the generic type, ...

Two things: first of all, depending on how you want to look at it, function isn't a method. It's just a function that happens to live in the trait's namespace (a.k.a. an "associated function").

Secondly, you're not trying to call function on the type, you're calling it on a value of that type. This is impossible because, again, it's not a method; it doesn't have a self parameter.

The solution is to actually call the function associated function on the generic type, which looks like this:

fn call_method<T: MyTrait>(object: T) {
    let x = T::function(2);
}

Sometimes, this won't be specific enough. If you need to be more specific, you can also write the above as:

fn call_method<T: MyTrait>(object: T) {
    let x = <T as MyTrait>::function(2);
}

The two are semantically identical; it's just that the second is more specific and more likely to resolve when you have lots of traits involved.

like image 153
DK. Avatar answered Oct 12 '22 23:10

DK.


Following on DK. answer, you don't actually need to pass "object: T" as an argument to your function.

You can just do

fn call_method<T: MyTrait>() {
    let x = T::function(2);
}

In fact, if I got it right, you are not passing this struct to the function but merely linking it through the T, so there is no move/borrow semantics involved. But I might be wrong here.

like image 44
Omar Abid Avatar answered Oct 13 '22 01:10

Omar Abid