println Examples (Console)Learn about the println macro to write strings and other variables to the console. Optimize console writing.
This page was last reviewed on Mar 29, 2023.
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.
Console Color
Println example. In this program we see the basic syntax for the println macro. It is important to include the exclamation mark at the end.
Version 1 We place the variable name from the surrounding block in between the braces in the println argument.
Version 2 We use separate arguments after empty braces. With this syntax, we can call functions or use more complex expressions.
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 performance. Each call to println (or print) has some overhead. If we merge together the print calls, we can improve overall program speed.
Version 1 We call println 100 times to print 100 lines to to the console output, and then display the time.
Version 2 We build up a String, and append 100 lines to it. Then we use print to write the string.
Tip Print does not append a newline to the output. Other than that it is the same as 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
Format. It is sometimes desirable to use format strings but not print them to the console. We can use the "format!" macro for this purpose.
Version 1 We print a formatted string to the console with println. The color "orange" is inserted into the brackets.
Version 2 We use format to create a 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
Literals. 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
Stdout. Sometimes we want to write data to the console that is not handled through println. This can be done by accessing stdout.
Vec extend from slice
Here We want to print a byte vector to the console in its raw representation as ASCII text.
Then We call 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"); }
Eprintln. 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.
And With the "eprintln!" macro, we can do that with the same syntax as 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
Writeln. This macro is like println but we can target a specific buffer. We must pass a mutable reference to a buffer (like a vector).
Tip Writeln can be used to avoid println calls to avoid locking (this can improve performance).
Next We receive a 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
Compile-time error. 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.
Thus We get a compile-time error when we pass invalid arguments to 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
Debug trait. 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 }
Summary. 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.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Mar 29, 2023 (new example).
© 2007-2024 Sam Allen.