Generic parameters in trait method, please help

I am still on this page Tour of Rust's Standard Library Traits | Generic Parameters, the last example. I'm reprinting it below:

--Starts--
Aside from parameterizing the trait it's also possible to parameterize individual functions and methods:

trait Trait {
    fn func<'a, T>(t: &'a T);
}

--Ends--

( Before posting this, I've also gone over this chapter Rust By Example | Generics, in its entirety. )

To understand this example, I wrote this little test program, I was expecting it to compile:

struct SomeType;

trait Trait {
    fn func<'a, T>(t: &'a T);
}

impl Trait for SomeType {
    fn func<'a, T>(t: &'a T) {
        println!("{:?}", t);
    }
}

fn main() {
    SomeType::func::<char>(&'a');
    // SomeType::func::<i32>(&78);
}

But both SomeType::func::<char>(&'a') and SomeType::func::<i32>(&78) fail to compile with error message:

error[E0277]: `T` doesn't implement `Debug`
...

I was expecting it to compile, because both primitives char and i32 implement std::fmt::Debug.

I was under the assumption that, at run time, the concrete type (?), i.e. <char> and <i32> would stand in place of generic T.

I also remember below statement, from Rust By Example | Generics | Bounds:

When working with generics, the type parameters often must use traits as bounds to stipulate what functionality a type implements.

-- But char and i32 already implement std::fmt::Debug.

Please help with this question: Why does the compiler reject this since char and i32 implement std::fmt::Debug?

The changed code below compiles:

struct SomeType;

trait Trait {
    fn func<'a, T: std::fmt::Debug>(t: &'a T);
}

impl Trait for SomeType {
    fn func<'a, T: std::fmt::Debug>(t: &'a T) {
        println!("{:?}", t);
    }
}

fn main() {
    SomeType::func::<char>(&'a');
    SomeType::func::<i32>(&78);
}

Thank you and best regards,

...behai.

Because the compiler verifies that your trait implementation is guaranteed to be valid.
It doesn't care that you're only using char and int32, that's kind of transient to it.
In the future, maybe other types will come into play.

By explicitly specifying that T must be Debug in your signature, the compiler can then be guaranteed that the implementation is always valid, because only Debug types are valid in the first place.

I was under the assumption that, at run time, the concrete type (?), i.e. <char> and <i32> would stand in place of generic T.

You're correct about this, but unlike other languages that just copy/paste the type in, Rust demands that your function be able to stand on it's own, even before it starts replacing T with any concrete types.

2 Likes

Your problem is unrelated to traits, let's simplify things a bit:

function func is something that can be called with a reference to any T with no restrictions, including things that are not Debug. To be able to use something in a function - you need to add a constraint.

2 Likes

You are confusing trait bounds with trait implementations.

For a rationale of why this is done, google "post-monomorphization error".

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.