Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why type need to be specified manually in this code, in rust?

Rust Playground

trait B<T> {}
impl<T> B<T> for T {}

fn f<K>()
where
    // u32: B<u32>, // 4
    u32: B<K>, // 3
{
    // get::<u32>(&1u32); // 2
    get(&1u32); // 1 error
}

fn get<Q>(k: &Q)
where
    u32: B<Q>,
{
}

fn main() {}

error at 1:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:10:9
   |
4  | fn f<K>()
   |      - expected this type parameter
...
10 |     get(&1u32); // 1 error
   |     --- ^^^^^ expected `&K`, found `&u32`
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected reference `&K`
              found reference `&u32`
note: function defined here
  --> src/main.rs:13:4
   |
13 | fn get<Q>(k: &Q)
   |    ^^^    -----

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

However, &u32 also satisfy trait bound of get.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

if I change 1 to 2, it is OK.

if I remove 3, it is OK.

if I add 4, it is OK.

Why?

I think it’s possible that the trait bound on f temporarily changed the constraints that already existed on u32, thus affecting the get function’s choice of the type parameter Q. If that’s the case, how did the u32 bound change? How does get select the type parameter?

Or is there a simpler way to understand it?

>Solution :

This is a case of a somewhat less-known detail of Rust’s inference: if there are two possible method candidates, and one of them comes from a trait bound of the function (and the other does not), Rust prefers the trait bound’s method, unless explicitly told otherwise.

In your case, there are two possible candidates for get::<_>(&u32) (written as get(&1u32)) in the generic parameter Q. The first is to choose Q = u32, the second being Q = K. Since the method requires u32: B<Q>, even though both satisfy this bound, Q = K is selected, because it comes from a trait bound in the caller method, while Q = u32 comes from the environment (the impl impl<T> B<T> for T).

This special case is done to aid inference in cases like the following:

fn foo<T: Into<String>>(v: T) {
    let s = v.into();
}

Here, the programmer obviously wants s to have type String. However, there are actually two candidates here: one being <T as Into<String>>::into(), but the other is the reflexive impl <T as Into<T>>::into(), provided by std. In order for this to not be ambiguous, Rust prefers the trait bound unless explicitly told otherwise.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading