Println
In Rust we print values to the console with the println
macro. This is the easiest way to output data—but faster approaches are available.
In Rust, each println
invocation will have overhead as it locks the underlying implementation. If we group together output lines, we can improve performance.
Println
exampleIn this program we see the basic syntax for the println
macro. It is important to include the exclamation mark at the end.
println
argument.fn main() { // Version 1: Print some content to the console. let count = 300; let value = "friend"; println!("Hello {value}: {count}"); // Version 2: Can use arguments instead. // Arguments can be more complex expressions. println!("Hello {}: {}", value, count + 1); }Hello friend: 300 Hello friend: 301
Println
performanceEach call to println
(or print) has some overhead. If we merge together the print calls, we can improve overall program speed.
println
100 times to print 100 lines to to the console output, and then display the time.String
, and append 100 lines to it. Then we use print to write the string
.println
.use std::time::Instant; fn main() { // Version 1: Use println 100 times. let t0 = Instant::now(); for _ in 0..100 { println!("Line"); } println!("{} ns", t0.elapsed().as_nanos()); // Version 2: Create a string with 100 lines, and use print once. let t1 = Instant::now(); let mut v = String::new(); for _ in 0..100 { v.push_str("Line"); v.push('\n'); } print!("{}", v); println!("{} ns", t1.elapsed().as_nanos()); }...Line Line Line 149916 ns ...Line Line Line 62792 ns
It is sometimes desirable to use format strings but not print them to the console. We can use the "format!" macro for this purpose.
string
to the console with println
. The color "orange" is inserted into the brackets.String
with the desired value, including the color string
.fn main() { let color = "orange"; // Version 1: use println with formatting. println!("The cat is {}", color); // Version 2: use format with println. let value = format!("The cat is {}", color); println!("{value}"); }The cat is orange The cat is orange
The println
macro supports string
literals with no substitutions. So we can print simple output with just one argument. And with no arguments, we get an empty line.
fn main() { // We can use string literals directly. // If no argument is passed, an empty line is printed. println!("Hi"); println!(); println!("Friends"); }Hi Friends
Sometimes we want to write data to the console that is not handled through println
. This can be done by accessing stdout.
byte
vector to the console in its raw representation as ASCII text.write_all()
with the byte
vector as the argument. We call except()
to handle the Result
from write_all
.use std::io; use std::io::*; fn main() { // A byte vector. let mut data = vec![]; data.extend_from_slice("Hello\n".as_bytes()); // Print all bytes to stdout. io::stdout().write_all(&data).expect("Invalid write"); }Hello
Console
programs have standard output and error output. If we have an error message we want to write, it may be better to write it to the error output.
println
.use std::fs::File; fn main() { if let Ok(_file) = File::open("/does/not/exist") { // Handle file. } else { // Write to error output. eprintln!("File not found"); } }File not found
This macro is like println
but we can target a specific buffer. We must pass a mutable reference to a buffer (like a vector).
println
calls to avoid locking (this can improve performance).Result
from writeln, which we test with is_err()
in our Rust program.use std::io::*; fn main() { let name = "Friend"; let mut buffer: Vec<u8> = vec![]; if writeln!(&mut buffer, "Hello {name}").is_err() { panic!("Write failed!"); } // Output the buffer as string. print!("{}", String::from_utf8_lossy(&buffer)); }Hello Friend
Println
is a macro, which means it is evaluated at compile-time and code is generated. This allows Rust to verify all the arguments are correct.
println
. This helps ensure a program, once built, is correct.fn main() { // Must have correct number of arguments to println. let test = 1; println!("{} {}", test); }error: 2 positional arguments in format string, but there is 1 argument
In Rust we cannot pass a struct
directly to println
unless it has the Debug trait implemented. We can do this with the derive Debug syntax on the struct
.
#[derive(Debug)] struct Item { width: usize, height: usize, } fn main() { let item = Item { width: 10, height: 12, }; // Print the struct with debug trait. println!("{:?}", item); }Item { width: 10, height: 12 }
Rust provides robust support for console writing in its standard library. We must become familiar with macro syntax. And merging together writes can improve performance.