4

I'm not trying to write sophisticated code, I just want to understand what is (or is not) going on here. I checked other questions but they all had complicated situations and I think this situation is the simplest so far.

I have the following code:

let one_step: f32 = "4.0".parse().unwrap();
let extra_step: u32 = one_step as u32;

println!("{:?}", extra_step);

The way I see it, we have a &str, we parse it to a f32 and unwrap it. Then we convert the f32 to a u32.

Why can't I just do this? Isn't this, practically, the same thing?

let single_step: u32 = "4.0".parse().unwrap() as u32;

println!("{:?}", single_step);

If I try to run this code, I get this error:

error[E0619]: the type of this value must be known in this context
 --> src/main.rs:6:27
  |
6 |     let single_step: u32 = "4.0".parse().unwrap() as u32;
  |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It looks like something requires us to break the operation into two chunks.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Omar Abid
  • 15,753
  • 28
  • 77
  • 108
  • 1
    Highly relevant: https://stackoverflow.com/q/27043268/1233251 and https://stackoverflow.com/q/47178016/1233251 – E_net4 Apr 04 '18 at 17:28
  • It is good practice to make a reproducible example in the [Rust Playground](//play.rust-lang.org), so that it can be run by everyone. – E_net4 Apr 04 '18 at 18:01
  • Also, yes, naming conventions are in the [Rust API guidelines](https://rust-lang-nursery.github.io/api-guidelines/naming.html). – E_net4 Apr 04 '18 at 18:01

1 Answers1

8

The thing is that parse isn't just defined for f32. parse can define all kind of types (specifically any type that implements FromStr). So how does Rust know that parse should return f32 and not for some other type?

In your first example it knows this because oneStep is declared to have type f32, so Rust can infer that it should call parse with f32 as its type argument. In the second example f32 isn't mentioned anywhere in the code, so Rust couldn't possibly figure it out.

Instead of inferring the type argument from the type of a variable, you can also pass it directly. That way it will work in a single step:

let singleStep: u32 = "4.0".parse::<f32>().unwrap() as u32;
sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • where can I find more info about the "turbofish" ::<> ? The parse documentation had just some light info about it and google didn't help much – Omar Abid Apr 04 '18 at 17:46
  • @OmarAbid It's just a somewhat strange syntax to pass type arguments. `parse` is defined as `parse() {...}` and `parse::` is a way to explicitly say that `T` should be `f32`. The more intuitive syntax `parse` would have led to grammar ambiguities with the `<` and `>` operators, so the "turbofish" was introduced instead. – sepp2k Apr 04 '18 at 17:51
  • I don't get it. parse is not getting any arguments. But we are here talking about the return type? – Omar Abid Apr 04 '18 at 18:08
  • @OmarAbid The point here is that Rust can infer parameter types from its "surroundings", not just from passed arguments. If we do `let x: i32 = "5".parse()?;`, the compiler can infer that `T` is `i32`. Regarding the turbofish, there is a brief mention in [`Iterator#collect`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.collect), where it is also commonly used. – E_net4 Apr 04 '18 at 18:11
  • @OmarAbid It is getting type arguments. As I said `parse` is defined as `parse() -> T {...}` (except I accidentally left out the `-> T` in my previous comment). So we have 0 value arguments (`()`), but one type argument ``. Some times type arguments can be inferred, but when they can't, you'll have to supply them manually. – sepp2k Apr 04 '18 at 18:12