g-var.com | G-VAR's Blog

Rust 1.2.2 | Display

Thu Jul 6, 2017

转载请注明出处!

译文链接:Rust 1.2.2 | Display

英文原文:Display


fmt::Debug看起来几乎是既不紧凑也不整洁,但通常利于进行输出形式的定制。而通过手动实现fmt::Display是可以实现紧凑又整洁的,其使用了{}输出标记。实现形式如下:

// (通过`use`)导入`fmt`模块来使其可见
use std::fmt;

// 定义一个用于实现`fmt::Display`的结构体,只是一个简单tuple struct,
// 包含一个绑定到名称为`Structure`结构体`i32`类型数据
struct Structure(i32);

// 为了使用`{}`标记,必须为此类型手动实现`fmt::Display`特性
impl fmt::Display for Structure {
    // 此特性需要`fmt`的确切签名
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // 直接将第一个元素写入提供的输出流:`f`中,
        // 返回一个`fmt::Result`,其表示了是否操作成功,
        // 注意`write!`的语法与`println!`类似。
        write!(f, "{}", self.0)
    }
}

fmt::Display可能会比fmt::Debug更整洁,但这暴露了std库的一个问题。模糊类型该如何显示?例如,如果std库为所有的Vec<T>实现了一个单一类型,那么该是何种风格?下面两种的一种?

  • Vec<path>:/:/etc:/home/username:/bin(以:分割)
  • Vec<number>:1,2,3(以,分割)

都不是,因为所有的类型都没有实际的风格,并且std库也不会假定一个。Vec<T>或者其它通用容器并没有实现fmt::Display。这些通用情况会使用fmt::Debug

这并不是个问题,因为任何新的容器类型都不是通用的,可以实现fmt::Display

use std::fmt; // 导入`fmt`

// 拥有两个数的结构体。继承了`Debug`,来与`Display`进行对比
#[derive(Debug)]
struct MinMax(i64, i64);

// 为`MinMax`实现`Display`
impl fmt::Display for MinMax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // 使用`self.number`来获取每个位置的数据
        write!(f, "({}, {})", self.0, self.1)
    }
}

// 定义一个具有具名域的结构体用于对比
#[derive(Debug)]
struct Point2D {
    x: f64,
    y: f64,
}

// 同样地,为Point2D实现`Display`
impl fmt::Display for Point2D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // 自定义输出,只表示出`x`和`y`
        write!(f, "x: {}, y: {}", self.x, self.y)
    }
}

fn main() {
    let minmax = MinMax(0, 14);

    println!("Compare structures:");
    println!("Display: {}", minmax);
    println!("Debug: {:?}", minmax);

    let big_range =   MinMax(-300, 300);
    let small_range = MinMax(-3, 3);

    println!("The big range is {big} and the small is {small}",
             small = small_range,
             big = big_range);

    let point = Point2D { x: 3.3, y: 7.2 };

    println!("Compare points:");
    println!("Display: {}", point);
    println!("Debug: {:?}", point);

    // 错误。`Debug`和`Display`都实现了,但`{:b}`的使用需要实现`fmt::Binary`,
    // 所以下面代码不起作用
    // println!("What does Point2D look like in binary: {:b}?", point);
}

所以,虽然实现了fmt::Display,但由于没有实现fmt::Binary,所以{:b}是不能用的。std::fmt具有很多类似的traits,并且每个都需要有自己的实现。在std::fmt中具有详细描述。

在检查了以上例子的输出之后,使用Point2D结构体作为范例,为例子增加一个复杂的结构体。以同样的形式打印输出,那么输出会如下形式:

Display: 3.3 + 7.2i
Debug: Complex { real: 3.3, imag: 7.2 }

请参考: derive, std::fmt, macros, struct, trait, 以及 use

[ 转载请在正文中标注并保留原文链接、译文链接等信息。]



Next: »