Output
Let's go back to our "hello world" programs, in Perl
#!/usr/bin/env perl
use v5.28;
use warnings;
say "Hello, World!";
and Rust
fn main() { println!("Hello, World!"); }
We see that println!
in Rust is like say
in Perl. There are similar things for print
and warn
.
Rust | Perl |
---|---|
print! | print |
println! | say |
eprint! | warn |
eprintln! | warn |
But for anything more complicated than a simple string like "Hello, World!" we need to format things first. In that sense, maybe a better analogy is to Perl's printf
and sprintf
Rust | Perl | TMTOWTDI |
---|---|---|
print! | print | printf |
println! | say | |
eprint! | warn | |
eprintln! | warn | |
format! | interpolation | sprintf |
Instead of interpolating the values of variables as in Perl
my $name = 'Tim';
say "Hello, $name!";
we format them like so
#![allow(unused_variables)] fn main() { let name = "Tim"; println!("Hello, {}!", name); }
The brackets are a placeholder for the value of name. To insert more variables, add more brackets.
#![allow(unused_variables)] fn main() { let name = "Tim"; let salutation = "Mr."; println!("Hello, {} {}!", salutation, name); }
(I don't think this is common elsewhere, but here in Baltimore I am much more likely to be called "Mr. Tim" than either "Mr. Heaney" or "Tim"; especially by younger people.) Anyway, there are lots more options, but you get the idea.
One of my favorite ways to show output while I'm working on Perl is with Data::Printer. We can achieve something similar with Rust's formatting.
#![allow(unused_variables)] fn main() { let name = "Tim"; let salutation = "Mr."; println!("Hello, {:?} {}!", salutation, name); }
When we run this, we get something slightly different. The {}
formatted the variable according to something called its Display
trait. But the {:?}
formats it according to its Debug
trait. It doesn't make much difference here, but in practice I find it indispensable.
I often use Data::Printer
in Perl to print out the values of complex data structures. It does that with clever introspection at run time. We can't do anything like that in Rust, but if we make sure the data structures we care about have a Debug trait (and there is a procedural macro that does exactly this for us), then we can just print them out with {:?}
. If they're very complex, we can print them out with {:#?}
, which is the same thing only prettier (arguably more like Data::Printer).
Rust | Perl |
---|---|
println!("{:#?}", foo) | use DDP; p $foo |
I've been using println!
everywhere (which is generally true in practice as well), but this format syntax is true for all of the above.
#![allow(unused_variables)] fn main() { // Format the string and return it. let greeting = format!("Hello, {} {}!", salutation, name); // Print the line to stderr, rather than stdout. eprintln!("Hello, {} {}!", salutation, name); }
There is also a handy little dbg!
macro, which prints out the variable name and value, along with the file name and line number, to stderr
Rust | Perl |
---|---|
dbg!(foo) | warn "\$foo = $foo" |
Update (2022-01-13): With the release of Rust 1.58, we can put captured identifiers in format strings! This is kind of like interpolation in Perl!
#![allow(unused_variables)] fn main() { let name = "Tim"; let salutation = "Mr."; println!("Hello, {salutation} {name}!"); }