Why is converting i32 to u64 fallible?

Hello,

Could someone explain to me why I have to use try_from here please?

In my mind, this operation should work because I dump a's value into the "bigger bucket" b.

More broadly, I'd like to understand when such a type conversion could fail (appart from having the value overflow or loss of precision)

Thanks :slight_smile:

fn main() {
    
    // OK
    let a: i32 = 1;
    let b = i64::from(a);
    println!("Got number: {}", b);
    
    // Fails so I have to use `try_from`, but why?
    let a: i32 = 1;
    let b = u64::from(a);
    println!("Got number: {}", b);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `u64: From<i32>` is not satisfied
  --> src/main.rs:10:13
   |
10 |     let b = u64::from(a);
   |             ^^^^^^^^^ the trait `From<i32>` is not implemented for `u64`
   |
   = help: the following implementations were found:
             <u64 as From<NonZeroU64>>
             <u64 as From<bool>>
             <u64 as From<char>>
             <u64 as From<u16>>
           and 71 others

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error

It's because the size of the types involved is not all that matters, it's also the value space.

Consider converting -1_i32 to u64.
That's a valid i32 value that's unrepresentable with u64, and hence a conversion from the former to the latter should fail.

6 Likes

Doh! Of course!! :man_facepalming:

Time to get off the keyboard.

Thanks @jjpe :grin:

4 Likes

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.