Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

Rust で println!("{}", x) で参照が自動的にデリファレンスされるやつと std::fmt::Display のやつのメモ

std::fmt::Display のやつ

println!("{:?}", x) で表示させるには derive(Debug) をしておけばよいが、println!("{}", x) では std::fmt::Display トレイトを実装している必要があるようだ。

#[derive(Debug)]
struct MyStruct(i32);

fn main() {
    let s = MyStruct(123);
    println!("{:?}", s);
    println!("{}", s);
}
> rustc b.rs
error[E0277]: `MyStruct` doesn't implement `std::fmt::Display`
 --> b.rs:7:20
  |
7 |     println!("{}", s);
  |                    ^ `MyStruct` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `MyStruct`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
  = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

std::fmt::Display を実装する。

use std::fmt;

#[derive(Debug)]
struct MyStruct(i32);

impl fmt::Display for MyStruct {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "i32: {}", self.0)
    }
}

fn main() {
    let s = MyStruct(123);
    println!("{:?}", s); // #[derive(Debug)] のおかげ
    println!("{}", s); // impl fmt::Display::fmt のおかげ
}
> .\b.exe   
MyStruct(123)
i32: 123
自動的にデリファレンスされるやつ

よく考えたらこれができるのっておかしくない?、と思った。

fn main() {
    let a = 5;
    let b = &a;
    let c = &b;
    let d = &c;

    // わかる
    assert_eq!(5, a);
    assert_eq!(5, *b);
    assert_eq!(5, **c);
    assert_eq!(5, ***d);

    // ?
    println!("a: {}", a);
    println!("b: {}, *b: {}", b, *b);
    println!("c: {}, *c: {}, **c: {}", c, *c, **c);
    println!("d: {}, *d: {}, **d: {}, ***d: {}", d, *d, **d, ***d);
}
a: 5
b: 5, *b: 5
c: 5, *c: 5, **c: 5
d: 5, *d: 5, **d: 5, ***d: 5

全部 5 。

これはつまり参照の型にも std::fmt::Display が実装されている、ということであっているのか?

プリミティブな型にもその参照の型にも std::fmt::Display が実装されていて、自動的に値までたどり着いて表示されているということか? 正直正確にはよくわかっていないけどわかったところまでとりあえずメモ。

参考:
How Does Rust's println! macro perform dereferencing? - Stack Overflow