25

How can a float value be converted to a String? For whatever reason, the documentation and all online sources I can find are only concerned with the other way around.

let value: f32 = 17.65;
let value_as_str: String = ..... 
Philipp Ludwig
  • 3,758
  • 3
  • 30
  • 48
  • And I bet that this is a duplicate, but I couldn't find a similar question. – Philipp Ludwig Sep 06 '17 at 22:02
  • 1
    Aside: In the land of C, printing a `float` to a string with enough, but not too many digits is accomplished with `sprintf(buf, sizeof buf, "%.*e", FLT_DECIMAL_DIG - 1, some_float);`. May provide some ideas for you. – chux - Reinstate Monica Sep 06 '17 at 22:08
  • I actually didn't know about C's ``FLT_DECIMAL``, so thanks for that. C++ has it even nicer with ``std::to_string``; I am looking for something similar to this in rust. – Philipp Ludwig Sep 06 '17 at 22:10
  • Note that `std::to_string` uses a fixed (non-exponential notation) that tends to convert a small `float` to "0.000000" and very large values with excessive digits. I wonder if `.to_string()` does the same? – chux - Reinstate Monica Sep 06 '17 at 22:15
  • It actually does, at least there at lot of excessive digits; figuring out how to format this will be the next step. – Philipp Ludwig Sep 06 '17 at 22:20
  • Converting a `float` to a string (in any language) and retain info about the value is best done with [exponential notation](https://en.wikipedia.org/wiki/Scientific_notation), else code is attempting to defeat the "floating" in "floating point". – chux - Reinstate Monica Sep 06 '17 at 22:33
  • 1
    I added examples to my answer on how to format using a fixed number of digits after the decimal point as well as how to format using exponential notation. – Lukas Kalbertodt Sep 06 '17 at 22:36
  • @LukasKalbertodt The `"3.1415926e6"` does not show how to print pi with an expected value of about `3.1415926e0`. The other trick is how many digits should be shown to present all `float` uniquely, yet without excessive decimal digits? Is 8 the right amount - as in your answer? (it is usually about 9 total digits in C) I know [how in C](https://stackoverflow.com/a/19897395/2410359), though unfamiliar in Rust, yet the principles are the same. – chux - Reinstate Monica Sep 06 '17 at 22:42

1 Answers1

48

Sometimes, the answer is easy: to_string().

let pi = 3.1415926;
let s = pi.to_string();  // : String

Background

The foundation for "creating a readable string representation of something" is in the fmt module. Probably the most important trait in this module is Display. Display is an abstraction over types that can be formatted as a user-facing string (pretty much exactly what you want). Usually the Display trait is used by println!() and friends. So you can already convert your float to string with the format!() macro:

let s = format!("{}", pi);

But there is something else: the ToString trait. This trait talks about types that can be converted to a String. And now, there is a magic implementation:

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

This means: every type which implements Display also automatically implements ToString! So instead of writing format!("{}", your_value) you can simply write your_value.to_string()!

While these wildcard implementations are extremely useful and versatile, they have one disadvantage: finding methods is much harder. As you point out, the documentation of f32 doesn't mention to_string() at all. This is not very good, but it is a known issue. We're trying to improve this situation!

Advanced formatting

The to_string() method uses the default formatting options, so it's equivalent to format!("{}", my_value). But sometimes, you want to tweak how the value is converted into a string. To do that, you have to use format!() and the full power of the fmt format specifier. You can read about those in the module documentation. One example:

let s = format!("{:.2}", pi);

This will result in a string with exactly two digits after the decimal point ("3.14").

If you want to convert your float into a string using scientific notation, you can use the {:e} (or {:E}) format specifier which corresponds to the LowerExp (or UpperExp) trait.

let s = format!("{:e}", pi * 1_000_000.0);

This will result in "3.1415926e6".

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • 2
    Thanks, I will accept your answer as soon as I can. Why is this not in the documentation for ``f32``? https://doc.rust-lang.org/std/primitive.f32.html – Philipp Ludwig Sep 06 '17 at 22:13
  • 2
    @PhilippLudwig I added a bunch of explanation. I hope this clarifies things :) – Lukas Kalbertodt Sep 06 '17 at 22:21
  • That actually does clarify the situation. Thank you very much for your effort! – Philipp Ludwig Sep 06 '17 at 22:22
  • _Sometimes, the answer is easy_. Well, but the output of e.g. `(1e-300).to_string()` is quite unexpected and different from how stringifying floats works in many other languages. Obtaining a human friendly string actually [does not seem to be straighforward](https://stackoverflow.com/q/59794031/1804173). – bluenote10 Jan 18 '20 at 10:39