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.

RustPerl
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

RustPerlTMTOWTDI
print!printprintf
println!say
eprint!warn
eprintln!warn
format!interpolationsprintf

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).

RustPerl
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

RustPerl
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}!");
}