Formatted Print in Rust

RustRustBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, the formatted print functionality in Rust is explained. The std::fmt module provides macros such as format!, print!, println!, eprint!, and eprintln! for handling printing tasks. These macros allow for formatting text with placeholders that are replaced with corresponding arguments. Positional and named arguments can be used, and different formatting can be applied using format characters. The macros also support justifying text, padding numbers, and setting the precision for decimal numbers. The fmt::Display trait is used to format text in a user-friendly way, while the fmt::Debug trait is used for debugging purposes. Rust also checks for formatting correctness at compile time. Additionally, it is mentioned that implementing the fmt::Display trait automatically implements the ToString trait, and custom types need to implement the fmt::Display trait to be printable. The lab also includes activities to practice using the formatted print macros and traits.

Note: If the lab does not specify a file name, you can use any file name you want. For example, you can use main.rs, compile and run it with rustc main.rs && ./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("`Rust`")) -.-> rust/BasicConceptsGroup(["`Basic Concepts`"]) rust(("`Rust`")) -.-> rust/DataTypesGroup(["`Data Types`"]) rust(("`Rust`")) -.-> rust/FunctionsandClosuresGroup(["`Functions and Closures`"]) rust(("`Rust`")) -.-> rust/MemorySafetyandManagementGroup(["`Memory Safety and Management`"]) rust(("`Rust`")) -.-> rust/AdvancedTopicsGroup(["`Advanced Topics`"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("`Variable Declarations`") rust/DataTypesGroup -.-> rust/integer_types("`Integer Types`") rust/DataTypesGroup -.-> rust/floating_types("`Floating-point Types`") rust/DataTypesGroup -.-> rust/string_type("`String Type`") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("`Function Syntax`") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("`Expressions and Statements`") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("`Lifetime Specifiers`") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("`Traits for Operator Overloading`") subgraph Lab Skills rust/variable_declarations -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/integer_types -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/floating_types -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/string_type -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/function_syntax -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/expressions_statements -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/lifetime_specifiers -.-> lab-99186{{"`Formatted Print in Rust`"}} rust/operator_overloading -.-> lab-99186{{"`Formatted Print in Rust`"}} end

Formatted print

Printing is handled by a series of macros defined in std::fmt some of which include:

  • format!: write formatted text to String.
  • print!: same as format! but the text is printed to the console (io::stdout).
  • println!: same as print! but a newline is appended.
  • eprint!: same as print! but the text is printed to the standard error (io::stderr).
  • eprintln!: same as eprint! but a newline is appended.

All parse text in the same fashion. As a plus, Rust checks formatting correctness at compile time.

fn main() {
    // In general, the `{}` will be automatically replaced with any
    // arguments. These will be stringified.
    println!("{} days", 31);

    // Positional arguments can be used. Specifying an integer inside `{}`
    // determines which additional argument will be replaced. Arguments start
    // at 0 immediately after the format string.
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // As can named arguments.
    println!("{subject} {verb} {object}",
             object="the lazy dog",
             subject="the quick brown fox",
             verb="jumps over");

    // Different formatting can be invoked by specifying the format character
    // after a `:`.
    println!("Base 10:               {}",   69420); // 69420
    println!("Base 2 (binary):       {:b}", 69420); // 10000111100101100
    println!("Base 8 (octal):        {:o}", 69420); // 207454
    println!("Base 16 (hexadecimal): {:x}", 69420); // 10f2c
    println!("Base 16 (hexadecimal): {:X}", 69420); // 10F2C

    // You can right-justify text with a specified width. This will
    // output "    1". (Four white spaces and a "1", for a total width of 5.)
    println!("{number:>5}", number=1);

    // You can pad numbers with extra zeroes,
    println!("{number:0>5}", number=1); // 00001
    // and left-adjust by flipping the sign. This will output "10000".
    println!("{number:0<5}", number=1); // 10000

    // You can use named arguments in the format specifier by appending a `$`.
    println!("{number:0>width$}", number=1, width=5);

    // Rust even checks to make sure the correct number of arguments are used.
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ Add the missing argument: "James"

    // Only types that implement fmt::Display can be formatted with `{}`. User-
    // defined types do not implement fmt::Display by default.

    #[allow(dead_code)] // disable `dead_code` which warn against unused module
    struct Structure(i32);

    // This will not compile because `Structure` does not implement
    // fmt::Display.
    // println!("This struct `{}` won't print...", Structure(3));
    // TODO ^ Try uncommenting this line

    // For Rust 1.58 and above, you can directly capture the argument from a
    // surrounding variable. Just like the above, this will output
    // "    1", 4 white spaces and a "1".
    let number: f64 = 1.0;
    let width: usize = 5;
    println!("{number:>width$}");
}

std::fmt contains many traits which govern the display of text. The base form of two important ones are listed below:

  • fmt::Debug: Uses the {:?} marker. Format text for debugging purposes.
  • fmt::Display: Uses the {} marker. Format text in a more elegant, user friendly fashion.

Here, we used fmt::Display because the std library provides implementations for these types. To print text for custom types, more steps are required.

Implementing the fmt::Display trait automatically implements the ToString trait which allows us to convert the type to String.

In line 43, #[allow(dead_code)] is an [attribute] which only apply to the module after it.

Activities

  • Fix the issue in the above code (see FIXME) so that it runs without error.
  • Try uncommenting the line that attempts to format the Structure struct (see TODO)
  • Add a println! macro call that prints: Pi is roughly 3.142 by controlling the number of decimal places shown. For the purposes of this exercise, use let pi = 3.141592 as an estimate for pi. (Hint: you may need to check the std::fmt documentation for setting the number of decimals to display)

Summary

Congratulations! You have completed the Formatted Print lab. You can practice more labs in LabEx to improve your skills.

Other Rust Tutorials you may like