Search code examples
rust

rust: generic function parameter type deduce


I'm reading a book on Rust and came across an example that looks like this.

use std::ops::{Deref, DerefMut};
use std::fmt::Display;

struct Selector<T> {
    elements: Vec<T>,
    current: usize
}

impl<T> Deref for Selector<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.elements[self.current]
    }
}

impl<T> DerefMut for Selector<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.elements[self.current]
    }
}

fn show_it_generic<T: Display> (thing: T) {
    println!("{}", thing);
}

fn main() {
    let s = Selector {elements: vec!["good", "bad", "ugly"], current: 2};
    show_it_generic(&s);
}

The compiler tells me that the type T is inferred as Selector<&str>, but I'm a bit confused by this. I believe it should be &Selector<&str>. Why does the error below occur?

error[E0277]: `Selector<&str>` doesn't implement `std::fmt::Display`
  --> src/main.rs:28:22
   |
28 |     show_it_generic(&s);
   |     ---------------  ^ `Selector<&str>` cannot be formatted with the default formatter
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `std::fmt::Display` is not implemented for `Selector<&str>`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: required for `&Selector<&str>` to implement `std::fmt::Display`
note: required by a bound in `show_it_generic`
  --> src/main.rs:22:23
   |
22 | fn show_it_generic<T: Display> (thing: T) {
   |                       ^^^^^^^ required by this bound in `show_it_generic`
help: consider dereferencing here
   |
28 |     show_it_generic(&*s);
   |                      +

For more information about this error, try `rustc --explain E0277`.
error: could not compile `code1` (bin "code1") due to previous error

Solution

  • Display has a blanket implementation for references:

    impl<T> Display for &T where
        T: Display + ?Sized
    

    In your call to show_it_generic(&s), Rust first matches this blanket implementation, then goes to check if the referred type T implements Display - which, in your case, it doesn't.