Expand description
Utilities for formatting and printingStrings.
This module contains the runtime support for theformat! syntax extension.This macro is implemented in the compiler to emit calls to this module inorder to format arguments at runtime into strings.
§Usage
Theformat! macro is intended to be familiar to those coming from C’sprintf/fprintf functions or Python’sstr.format function.
Some examples of theformat! extension are:
format!("Hello");// => "Hello"format!("Hello, {}!","world");// => "Hello, world!"format!("The number is {}",1);// => "The number is 1"format!("{:?}", (3,4));// => "(3, 4)"format!("{value}", value=4);// => "4"letpeople ="Rustaceans";format!("Hello {people}!");// => "Hello Rustaceans!"format!("{} {}",1,2);// => "1 2"format!("{:04}",42);// => "0042" with leading zerosformat!("{:#?}", (100,200));// => "( // 100, // 200, // )"From these, you can see that the first argument is a format string. It isrequired by the compiler for this to be a string literal; it cannot be avariable passed in (in order to perform validity checking). The compilerwill then parse the format string and determine if the list of argumentsprovided is suitable to pass to this format string.
To convert a single value to a string, use theto_string method. Thiswill use theDisplay formatting trait.
§Positional parameters
Each formatting argument is allowed to specify which value argument it’sreferencing, and if omitted it is assumed to be “the next argument”. Forexample, the format string{} {} {} would take three parameters, and theywould be formatted in the same order as they’re given. The format string{2} {1} {0}, however, would format arguments in reverse order.
Things can get a little tricky once you start intermingling the two types ofpositional specifiers. The “next argument” specifier can be thought of as aniterator over the argument. Each time a “next argument” specifier is seen,the iterator advances. This leads to behavior like this:
The internal iterator over the argument has not been advanced by the timethe first{} is seen, so it prints the first argument. Then upon reachingthe second{}, the iterator has advanced forward to the second argument.Essentially, parameters that explicitly name their argument do not affectparameters that do not name an argument in terms of positional specifiers.
A format string is required to use all of its arguments, otherwise it is acompile-time error. You may refer to the same argument more than once in theformat string.
§Named parameters
Rust itself does not have a Python-like equivalent of named parameters to afunction, but theformat! macro is a syntax extension that allows it toleverage named parameters. Named parameters are listed at the end of theargument list and have the syntax:
identifier '=' expressionFor example, the followingformat! expressions all use named arguments:
format!("{argument}", argument ="test");// => "test"format!("{name} {}",1, name =2);// => "2 1"format!("{a} {c} {b}", a="a", b='b', c=3);// => "a 3 b"If a named parameter does not appear in the argument list,format! willreference a variable with that name in the current scope.
letargument =2+2;format!("{argument}");// => "4"fnmake_string(a: u32, b:&str) -> String {format!("{b} {a}")}make_string(927,"label");// => "label 927"It is not valid to put positional parameters (those without names) afterarguments that have names. Like with positional parameters, it is notvalid to provide named parameters that are unused by the format string.
§Formatting Parameters
Each argument being formatted can be transformed by a number of formattingparameters (corresponding toformat_spec inthe syntax). Theseparameters affect the string representation of what’s being formatted.
The colon: in format syntax divides identifier of the input data andthe formatting options, the colon itself does not change anything, onlyintroduces the options.
§Width
// All of these print "Hello x !"println!("Hello {:5}!","x");println!("Hello {:1$}!","x",5);println!("Hello {1:0$}!",5,"x");println!("Hello {:width$}!","x", width =5);letwidth =5;println!("Hello {:width$}!","x");This is a parameter for the “minimum width” that the format should take up.If the value’s string does not fill up this many characters, then thepadding specified by fill/alignment will be used to take up the requiredspace (see below).
The value for the width can also be provided as ausize in the list ofparameters by adding a postfix$, indicating that the second argument isausize specifying the width.
Referring to an argument with the dollar syntax does not affect the “nextargument” counter, so it’s usually a good idea to refer to arguments byposition, or use named arguments.
§Fill/Alignment
assert_eq!(format!("Hello {:<5}!","x"),"Hello x !");assert_eq!(format!("Hello {:-<5}!","x"),"Hello x----!");assert_eq!(format!("Hello {:^5}!","x"),"Hello x !");assert_eq!(format!("Hello {:>5}!","x"),"Hello x!");The optional fill character and alignment is provided normally in conjunction with thewidth parameter. It must be defined beforewidth, right after the:.This indicates that if the value being formatted is smaller thanwidth some extra characters will be printed around it.Filling comes in the following variants for different alignments:
[fill]<- the argument is left-aligned inwidthcolumns[fill]^- the argument is center-aligned inwidthcolumns[fill]>- the argument is right-aligned inwidthcolumns
The defaultfill/alignment for non-numerics is a space andleft-aligned. Thedefault for numeric formatters is also a space character but with right-alignment. Ifthe0 flag (see below) is specified for numerics, then the implicit fill character is0.
Note that alignment might not be implemented by some types. In particular, itis not generally implemented for theDebug trait. A good way to ensurepadding is applied is to format your input, then pad this resulting stringto obtain your output:
§Sign/#/0
assert_eq!(format!("Hello {:+}!",5),"Hello +5!");assert_eq!(format!("{:#x}!",27),"0x1b!");assert_eq!(format!("Hello {:05}!",5),"Hello 00005!");assert_eq!(format!("Hello {:05}!", -5),"Hello -0005!");assert_eq!(format!("{:#010x}!",27),"0x0000001b!");These are all flags altering the behavior of the formatter.
+- This is intended for numeric types and indicates that the signshould always be printed. By default only the negative sign of signed valuesis printed, and the sign of positive or unsigned values is omitted.This flag indicates that the correct sign (+or-) should always be printed.-- Currently not used#- This flag indicates that the “alternate” form of printing shouldbe used. The alternate forms are:#?- pretty-print theDebugformatting (adds linebreaks and indentation)#x- precedes the argument with a0x#X- precedes the argument with a0x#b- precedes the argument with a0b#o- precedes the argument with a0o
SeeFormatting traits for a description of what the
?,x,X,b, andoflags do.0- This is used to indicate for integer formats that the padding towidthshouldboth be done with a0character as well as be sign-aware. A formatlike{:08}would yield00000001for the integer1, while thesame format would yield-0000001for the integer-1. Notice thatthe negative version has one fewer zero than the positive version.Note that padding zeros are always placed after the sign (if any)and before the digits. When used together with the#flag, a similarrule applies: padding zeros are inserted after the prefix but beforethe digits. The prefix is included in the total width.This flag overrides thefill character and alignment flag.
§Precision
For non-numeric types, this can be considered a “maximum width”. If the resulting string islonger than this width, then it is truncated down to this many characters and that truncatedvalue is emitted with properfill,alignment andwidth if those parameters are set.
For integral types, this is ignored.
For floating-point types, this indicates how many digits after the decimal point should beprinted.
There are three possible ways to specify the desiredprecision:
An integer
.N:the integer
Nitself is the precision.An integer or name followed by dollar sign
.N$:use formatargument
N(which must be ausize) as the precision.An asterisk
.*:.*means that this{...}is associated withtwo format inputs rather than one:- If a format string in the fashion of
{:<spec>.*}is used, then the first input holdstheusizeprecision, and the second holds the value to print. - If a format string in the fashion of
{<arg>:<spec>.*}is used, then the<arg>partrefers to the value to print, and theprecisionis taken like it was specified with anomitted positional parameter ({}instead of{<arg>:}).
- If a format string in the fashion of
For example, the following calls all print the same thingHello x is 0.01000:
// Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}println!("Hello {0} is {1:.5}","x",0.01);// Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}println!("Hello {1} is {2:.0$}",5,"x",0.01);// Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}println!("Hello {0} is {2:.1$}","x",5,0.01);// Hello {next arg -> arg 0 ("x")} is {second of next two args -> arg 2 (0.01) with precision// specified in first of next two args -> arg 1 (5)}println!("Hello {} is {:.*}","x",5,0.01);// Hello {arg 1 ("x")} is {arg 2 (0.01) with precision// specified in next arg -> arg 0 (5)}println!("Hello {1} is {2:.*}",5,"x",0.01);// Hello {next arg -> arg 0 ("x")} is {arg 2 (0.01) with precision// specified in next arg -> arg 1 (5)}println!("Hello {} is {2:.*}","x",5,0.01);// Hello {next arg -> arg 0 ("x")} is {arg "number" (0.01) with precision specified// in arg "prec" (5)}println!("Hello {} is {number:.prec$}","x", prec =5, number =0.01);While these:
println!("{}, `{name:.*}` has 3 fractional digits","Hello",3, name=1234.56);println!("{}, `{name:.*}` has 3 characters","Hello",3, name="1234.56");println!("{}, `{name:>8.*}` has 3 right-aligned characters","Hello",3, name="1234.56");print three significantly different things:
Hello, `1234.560` has 3 fractional digitsHello, `123` has 3 charactersHello, ` 123` has 3 right-aligned charactersWhen truncating these values, Rust usesround half-to-even,which is the default rounding mode in IEEE 754.For example,
Would return:
1.234e41.236e4§Localization
In some programming languages, the behavior of string formatting functionsdepends on the operating system’s locale setting. The format functionsprovided by Rust’s standard library do not have any concept of locale andwill produce the same results on all systems regardless of userconfiguration.
For example, the following code will always print1.5 even if the systemlocale uses a decimal separator other than a dot.
§Escaping
The literal characters{ and} may be included in a string by precedingthem with the same character. For example, the{ character is escaped with{{ and the} character is escaped with}}.
§Syntax
To summarize, here you can find the full grammar of format strings.The syntax for the formatting language used is drawn from other languages,so it should not be too alien. Arguments are formatted with Python-likesyntax, meaning that arguments are surrounded by{} instead of the C-like%. The actual grammar for the formatting syntax is:
format_string := text [ maybe_format text ] *maybe_format := '{' '{' | '}' '}' | formatformat := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}'argument := integer | identifierformat_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]fill := characteralign := '<' | '^' | '>'sign := '+' | '-'width := countprecision := count | '*'type := '?' | 'x?' | 'X?' | 'o' | 'x' | 'X' | 'p' | 'b' | 'e' | 'E'count := parameter | integerparameter := argument '$'In the above grammar,
textmust not contain any'{'or'}'characters,wsis any character for whichchar::is_whitespacereturnstrue, has no semanticmeaning and is completely optional,integeris a decimal integer that may contain leading zeroes and must fit into anusizeandidentifieris anIDENTIFIER_OR_KEYWORD(not anIDENTIFIER) as defined by theRust language reference.
§Formatting traits
When requesting that an argument be formatted with a particular type, youare actually requesting that an argument ascribes to a particular trait.This allows multiple actual types to be formatted via{:x} (likei8 aswell asisize). The current mapping of types to traits is:
- nothing ⇒
Display ?⇒Debugx?⇒Debugwith lower-case hexadecimal integersX?⇒Debugwith upper-case hexadecimal integerso⇒Octalx⇒LowerHexX⇒UpperHexp⇒Pointerb⇒Binarye⇒LowerExpE⇒UpperExp
What this means is that any type of argument which implements thefmt::Binary trait can then be formatted with{:b}. Implementationsare provided for these traits for a number of primitive types by thestandard library as well. If no format is specified (as in{} or{:6}),then the format trait used is theDisplay trait.
When implementing a format trait for your own type, you will have toimplement a method of the signature:
Your type will be passed asself by-reference, and then the functionshould emit output into the Formatterf which implementsfmt::Write. It is up to eachformat trait implementation to correctly adhere to the requested formatting parameters.The values of these parameters can be accessed with methods of theFormatter struct. In order to help with this, theFormatter struct alsoprovides some helper methods.
Additionally, the return value of this function isfmt::Result which is atype alias ofResult<(),std::fmt::Error>. Formatting implementationsshould ensure that they propagate errors from theFormatter (e.g., whencallingwrite!). However, they should never return errors spuriously. Thatis, a formatting implementation must and may only return an error if thepassed-inFormatter returns an error. This is because, contrary to whatthe function signature might suggest, string formatting is an infallibleoperation. This function only returns aResult because writing to theunderlying stream might fail and it must provide a way to propagate the factthat an error has occurred back up the stack.
An example of implementing the formatting traits would looklike:
usestd::fmt;#[derive(Debug)]structVector2D { x: isize, y: isize,}implfmt::DisplayforVector2D {fnfmt(&self, f:&mutfmt::Formatter<'_>) -> fmt::Result {// The `f` value implements the `Write` trait, which is what the // write! macro is expecting. Note that this formatting ignores the // various flags provided to format strings.write!(f,"({}, {})",self.x,self.y) }}// Different traits allow different forms of output of a type. The meaning// of this format is to print the magnitude of a vector.implfmt::BinaryforVector2D {fnfmt(&self, f:&mutfmt::Formatter<'_>) -> fmt::Result {letmagnitude = (self.x *self.x +self.y *self.y)asf64;letmagnitude = magnitude.sqrt();// Respect the formatting flags by using the helper method // `pad_integral` on the Formatter object. See the method // documentation for details, and the function `pad` can be used // to pad strings.letdecimals = f.precision().unwrap_or(3);letstring =format!("{magnitude:.decimals$}"); f.pad_integral(true,"",&string) }}fnmain() {letmyvector = Vector2D { x:3, y:4};println!("{myvector}");// => "(3, 4)"println!("{myvector:?}");// => "Vector2D {x: 3, y:4}"println!("{myvector:10.3b}");// => " 5.000"}§fmt::Display vsfmt::Debug
These two formatting traits have distinct purposes:
fmt::Displayimplementations assert that the type can be faithfullyrepresented as a UTF-8 string at all times. It isnot expected thatall types implement theDisplaytrait.fmt::Debugimplementations should be implemented forall public types.Output will typically represent the internal state as faithfully as possible.The purpose of theDebugtrait is to facilitate debugging Rust code. Inmost cases, using#[derive(Debug)]is sufficient and recommended.
Some examples of the output from both traits:
assert_eq!(format!("{} {:?}",3,4),"3 4");assert_eq!(format!("{} {:?}",'a','b'),"a 'b'");assert_eq!(format!("{} {:?}","foo\n","bar\n"),"foo\n \"bar\\n\"");§Related macros
There are a number of related macros in theformat! family. The ones thatare currently implemented are:
format!// described abovewrite!// first argument is either a &mut io::Write or a &mut fmt::Write, the destinationwriteln!// same as write but appends a newlineprint!// the format string is printed to the standard outputprintln!// same as print but appends a newlineeprint!// the format string is printed to the standard erroreprintln!// same as eprint but appends a newlineformat_args!// described below.§write!
write! andwriteln! are two macros which are used to emit the format stringto a specified stream. This is used to prevent intermediate allocations offormat strings and instead directly write the output. Under the hood, thisfunction is actually invoking thewrite_fmt function defined on thestd::io::Write and thestd::fmt::Write trait. Example usage is:
§print!
This andprintln! emit their output to stdout. Similarly to thewrite!macro, the goal of these macros is to avoid intermediate allocations whenprinting output. Example usage is:
§eprint!
Theeprint! andeprintln! macros are identical toprint! andprintln!, respectively, except they emit theiroutput to stderr.
§format_args!
format_args! is a curious macro used to safely pass aroundan opaque object describing the format string. This objectdoes not require any heap allocations to create, and it onlyreferences information on the stack. Under the hood, all ofthe related macros are implemented in terms of this. Firstoff, some example usage is:
usestd::fmt;usestd::io::{self, Write};letmutsome_writer = io::stdout();write!(&mutsome_writer,"{}",format_args!("print with a {}","macro"));fnmy_fmt_fn(args: fmt::Arguments<'_>) {write!(&mutio::stdout(),"{args}");}my_fmt_fn(format_args!(", or a {} too","function"));The result of theformat_args! macro is a value of typefmt::Arguments.This structure can then be passed to thewrite andformat functionsinside this module in order to process the format string.The goal of this macro is to even further prevent intermediate allocationswhen dealing with formatting strings.
For example, a logging library could use the standard formatting syntax, butit would internally pass around this structure until it has been determinedwhere output should go to.
Structs§
- Arguments
- This structure represents a safely precompiled version of a format stringand its arguments. This cannot be generated at runtime because it cannotsafely be done, so no constructors are given and the fields are privateto prevent modification.
- Debug
List - A struct to help with
fmt::Debugimplementations. - Debug
Map - A struct to help with
fmt::Debugimplementations. - Debug
Set - A struct to help with
fmt::Debugimplementations. - Debug
Struct - A struct to help with
fmt::Debugimplementations. - Debug
Tuple - A struct to help with
fmt::Debugimplementations. - Error
- The error type which is returned from formatting a message into a stream.
- Formatter
- Configuration for formatting.
- FromFn
- Implements
fmt::Debugandfmt::Displayvia the provided closure. - Formatting
Options Experimental - Options for formatting.
Enums§
- Alignment
- Possible alignments returned by
Formatter::align - Debug
AsHex Experimental - Specifies whether the
Debugtrait should use lower-/upper-casehexadecimal or normal integers. - Sign
Experimental - The signedness of a
Formatter(or of aFormattingOptions).
Traits§
- Binary
bformatting.- Debug
?formatting.- Display
- Format trait for an empty format,
{}. - Lower
Exp eformatting.- Lower
Hex xformatting.- Octal
oformatting.- Pointer
pformatting.- Upper
Exp Eformatting.- Upper
Hex Xformatting.- Write
- A trait for writing or formatting into Unicode-accepting buffers or streams.
Functions§
- format
- Takes an
Argumentsstruct and returns the resulting formatted string. - from_fn
- Creates a type whose
fmt::Debugandfmt::Displayimpls areforwarded to the provided closure. - write
- Takes an output stream and an
Argumentsstruct that can be precompiled withtheformat_args!macro.
Type Aliases§
- Result
- The type returned by formatter methods.
Derive Macros§
- Debug
- Derive macro generating an impl of the trait
Debug.