I am trying to find the "correct" Rust approach to this problem.
The original problem I faced was that I have a method that gets called to print out some values, the exact format depending on a number of options. I needed to add support for some new options. Not all options work with all types of values but there are runtime checks to confirm the options in use are valid for the values passed before my method is called.
If I was doing it in C I would create a printf
style format string at runtime, based on the options, and call printf
. print!
et al don't allow runtime defined format strings though. My next idea was to have a series of print!
calls with different static format strings and use if or match to control which was called.
My simplified version of this is:
fn print<T>(number: T, hex: bool) -> ()
where
T: std::fmt::Display + std::fmt::LowerHex
{
if hex {
println!("{:x}", number);
} else {
println!("{}", number);
}
}
fn main() -> ()
{
print(10, false);
print(10, true);
//print(3.1415, false);
}
If I uncomment the float however then this fails to compile because floats don't implement the LowerHex
trait. We know that it is safe though, as hex
is false and so the trait won't be needed - but I'm not sure if the compiler can be convinced of this?
I could presumably create a trait that has a method for each of the different sorts of format strings needed and then implement it for (in this case) both ints and floats, but in the float case call panic!
in methods that need hex conversion. That seems a bit hacky (and very verbose beyond this simple example) though.
I could presumably also use unsafe
to call printf from libc. Or implement my own formatting routines. Neither seem like they are the proper approach.
Is there a nicer solution? I guess the fundamental problem is that floats and ints are both numbers to a human but totally different beasts when it comes to formatting.