Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I not implement a trait for references to implementors of that trait?

If I have a trait, and a function that accepts a generic type constrained to that type, everything works fine. If I try to pass in a reference to that type, I get a compilation error.

trait Trait {
    fn hello(&self) -> u32;
}

struct Struct(u32);

impl Trait for Struct {
    fn hello(&self) -> u32 {
        self.0
    }
}

fn runner<T: Trait>(t: T) {
    println!("{}", t.hello())
}

fn main() {
    let s = Struct(42);

    // Works
    runner(s);

    // Doesn't work
    runner(&s);
}
error[E0277]: the trait bound `&Struct: Trait` is not satisfied
  --> src/main.rs:24:5
   |
24 |     runner(&s);
   |     ^^^^^^ the trait `Trait` is not implemented for `&Struct`
   |
   = help: the following implementations were found:
             <Struct as Trait>
note: required by `runner`
  --> src/main.rs:13:1
   |
13 | fn runner<T: Trait>(t: T) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^

I can fix the issue by implementing the trait for any reference to a type that implements the trait:

impl<'a, T> Trait for &'a T
where
    T: Trait,
{
    fn hello(&self) -> u32 {
        (*self).hello()
    }
}

The piece of information that I'm missing is when shouldn't I implement this? Asked another way, why doesn't the compiler automatically implement this for me? Since it currently doesn't, I assume there must be cases where having this implementation would be disadvantageous.

like image 621
Shepmaster Avatar asked Mar 01 '15 21:03

Shepmaster


People also ask

When should I use traits Rust?

We can use traits as function parameters to allow the function to accept any type that can do x , where x is some behavior defined by a trait. We can also use trait bounds to refine and restrict generics, such as by saying we accept any type T that implements a specified trait.

What is the point of traits in Rust?

A trait in Rust is a group of methods that are defined for a particular type. Traits are an abstract definition of shared behavior amongst different types. So, in a way, traits are to Rust what interfaces are to Java or abstract classes are to C++. A trait method is able to access other methods within that trait.

What is Rust implementation?

An implementation is an item that associates items with an implementing type. Implementations are defined with the keyword impl and contain functions that belong to an instance of the type that is being implemented or to the type statically. There are two types of implementations: inherent implementations.

What is a blanket implementation in Rust?

What are blanket implementations? Blanket implementations leverage Rust's ability to use generic parameters. They can be used to define shared behavior using traits. This is a great way to remove redundancy in code by reducing the need to repeat the code for different types with similar functionality.


2 Answers

when shouldn't I implement this? Asked another way, why doesn't the compiler automatically implement this for me? Since it currently doesn't, I assume there must be cases where having this implementation would be disadvantageous.

As an example, the Default trait immediately came to mind.

pub trait Default {
    fn default() -> Self;
}

I could implement it for T, but there is no way to automatically implement it for &T.

like image 106
swizard Avatar answered Nov 28 '22 06:11

swizard


The particular trait you are writing here only takes self by reference, and that is the only reason it is possible to write the additional implementation you did.

For this reason, taking the parameter to runner() by value is probably undesirable; you should instead be taking it by reference. This guideline can apply generally: if it is possible to implement the trait for a reference then rather than wondering “should I implement it?” you should wonder “why would I implement it?” for the only cases where you would use it should probably be altered to take the object by reference in the first place.

like image 42
Chris Morgan Avatar answered Nov 28 '22 06:11

Chris Morgan