Rust by Example — страница 2 из 66

convert the type to String.

Activities

   • Fix the two issues in the above code (see FIXME) so that it runs without error.

   • Add a println! macro 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)

See also:

std::fmt, macros, struct, and traits

Debug

All types which want to use std::fmt formatting traits require an implementation to be printable. Automatic implementations are only provided for types such as in the std library. All others must be manually implemented somehow.

The fmt::Debug trait makes this very straightforward. All types can derive (automatically create) the fmt::Debug implementation. This is not true for fmt::Display which must be manually implemented.


#![allow(unused)]

fn main() {

// This structure cannot be printed either with `fmt::Display` or

// with `fmt::Debug`.

struct UnPrintable(i32);


// The `derive` attribute automatically creates the implementation

// required to make this `struct` printable with `fmt::Debug`.

#[derive(Debug)]

struct DebugPrintable(i32);

}

All std library types are automatically printable with {:?} too:

// Derive the `fmt::Debug` implementation for `Structure`. `Structure`

// is a structure which contains a single `i32`.

#[derive(Debug)]

struct Structure(i32);

// Put a `Structure` inside of the structure `Deep`. Make it printable

// also.

#[derive(Debug)]

struct Deep(Structure);

fn main() {

// Printing with `{:?}` is similar to with `{}`.

println!("{:?} months in a year.", 12);

println!("{1:?} {0:?} is the {actor:?} name.",

"Slater",

"Christian",

actor="actor's");

// `Structure` is printable!

println!("Now {:?} will print!", Structure(3));

// The problem with `derive` is there is no control over how

// the results look. What if I want this to just show a `7`?

println!("Now {:?} will print!", Deep(Structure(7)));

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

So fmt::Debug definitely makes this printable but sacrifices some elegance. Rust also provides "pretty printing" with {:#?}.

#[derive(Debug)]

struct Person<'a> {

name: &'a str,

age: u8

}

fn main() {

let name = "Peter";

let age = 27;

let peter = Person { name, age };

// Pretty print

println!("{:#?}", peter);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

One can manually implement fmt::Display to control the display.

See also:

attributes, derive, std::fmt, and struct

Display

fmt::Debug hardly looks compact and clean, so it is often advantageous to customize the output appearance. This is done by manually implementing fmt::Display, which uses the {} print marker. Implementing it looks like this:


#![allow(unused)]

fn main() {

// Import (via `use`) the `fmt` module to make it available.

use std::fmt;


// Define a structure for which `fmt::Display` will be implemented. This is

// a tuple struct named `Structure` that contains an `i32`.

struct Structure(i32);


// To use the `{}` marker, the trait `fmt::Display` must be implemented

// manually for the type.

impl fmt::Display for Structure {

// This trait requires `fmt` with this exact signature.

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

// Write strictly the first element into the supplied output

// stream: `f`. Returns `fmt::Result` which indicates whether the

// operation succeeded or failed. Note that `write!` uses syntax which

// is very similar to `println!`.

write!(f, "{}", self.0)

}

}

}

fmt::Display may be cleaner than fmt::Debug but this presents a problem for the std library. How should ambiguous types be displayed? For example, if the std library implemented a single style for all Vec, what style should it be? Would it be either of these two?

   • Vec: /:/etc:/home/username:/bin (split on :)

   • Vec: 1,2,3 (split on ,)

No, because there is no ideal style for all types and the std library doesn't presume to dictate one. fmt::Display is not implemented for Vec or for any other generic containers. fmt::Debug must then be used for these generic cases.

This is not a problem though because for any new container type which is not generic,fmt::Display can be implemented.

use std::fmt; // Import `fmt`

// A structure holding two numbers. `Debug` will be derived so the results can

// be contrasted with `Display`.

#[derive(Debug)]

struct MinMax(i64, i64);

// Implement `Display` for `MinMax`.

impl fmt::Display for MinMax {

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

// Use `self.number` to refer to each positional data point.

write!(f, "({}, {})", self.0, self.1)

}

}

// Define a structure where the fields are nameable for comparison.

#[derive(Debug)]

struct Point2D {

x: f64,

y: f64,

}

// Similarly, implement `Display` for `Point2D`

impl fmt::Display for Point2D {

fn fmt(