Search code examples
rusttraits

What is this: `impl<T> Trait for T {}`?


Recently, I saw different places where this was given as example code, and writing it in my editor, it seems to be valid code.

trait Trait {}

impl<T> Trait for T {}

I can't seem to find any documentation explaining this; I'm sure it exists, but I don't really know what to google.

How would you instantiate T to and then call any methods within the impl block?

I'm sure there is a good reason for this, but I can't seem to wrap my head around it, would anyone be able to link the relevant documentation for this feature in rust?


I realise from the answers that I may have not been clear; I had copied the example from what I’ve seen.

Though from the first answer, I realised that the below code is also valid, and perhaps a more clear representation of what I’m trying to ask, which is, what is the use for the generics syntax that allows this code to be valid:

trait Trait {
    fn test() -> String {
        "test".to_string()
    }
}

impl<T> Trait for T {}

Does this affect existing structs and enums in the file, or does it literally just do absolutely nothing, and can never be called or used?


Solution

  • This code is showing you two things: marker traits and blanket implementations.

    trait Foo {} (with no trait members) declares a marker trait which serves only to tag certain types. The built-in traits Copy, Send, and Sync are good examples of marker traits.

    impl<T> Foo for T {} implements the trait Foo for all types, a so-called blanket implementation.

    Together, this is pretty much redundant, because there isn't a difference between "type that implements Foo" and "all types."

    However, seemingly-useless blanket implementations can actually be useful in practice. In the Rust standard library, there is a blanket implementation impl<T> From<T> for T which tells Rust "you can convert any T to T." This is not useful on its own, but winds up being useful in generic code, such as fn foo(arg: impl Into<i32>) which lets you pass an argument of any type that can be infallibly converted to i32. Because of the blanket implementation, this includes i32 itself.

    How would you instantiate T to then call any methods within the impl block?

    Well, the body of the impl block can't have anything in this case. The body of an impl ... for block is to implement trait members, but the trait being implemented has no members.

    If we assume that the trait does have members, then the answer to your question would be that you would have to bound T in a way that lets you perform operations on it. For example, to create a T you could choose to add the bound T: Default which would let you call T::default() to create an instance of T with a (type-defined) default value.

    Note that adding bounds on T would change the scope of the implementation to only apply to types that satisfy the bounds. This is very common in practice. For example, the implementation of Clone on Vec<T> is bounded on T: Clone. (How would you clone a vector if you can't clone its elements, after all?)


    Further reading: