概要
Rustでは簡単にprintするためのDebug
ときれいにprintするためのDisplay
という2つのtraitがあります。
初心者ながら、これらを調べるのに苦労したので、書き残しておきます。
簡単に、次のような単方向リストで例示します。メソッドの実装は割愛します。
#[derive(Debug)]
struct List<T> {
head: Option<Box<Node<T>>>,
}
#[derive(Debug)]
struct Node<T> {
value: T,
next: Option<Box<Node<T>>>,
}
Debugの場合
上のように#[derive(Debug)]
とすることにより簡単に実装されます。使うときは{:?}
とすることに注意!
また、dbg!
マクロも便利です(eprintln!
と同じくstderrに出力され、何行目の出力かも出る。詳しくはRustのdbg!マクロについて)。
let mut list = List::new();
for i in &[1, 2, 3] {
list.push_back(i);
}
println!("{:?}", &list); // 表示結果 List { head: Some(Node { value: 1, next: Some(Node { value: 2, next: Some(Node { value: 3, next: None }) }) })
dbg!(&list); // これでもよい
#Displayの場合
次のように実装してみます。結構やってみると難しいです。Node
に入っている値がDisplay
を実装していないと難しいので<T: fmt::Display>
としています。
use std::fmt;
impl<T: fmt::Display> fmt::Display for List<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut node = match self.head {
None => return write!(f, "has no nodes"),
Some(ref b) => {
let _ = write!(f, "{} ", &b.value); // 結果を明示的に捨てないとwarnが出る
b.as_ref()
}
};
while let Some(ref b) = node.next {
let _ = write!(f, "{} ", &b.value);
node = b.as_ref();
}
write!(f, "") // 上で結果を捨てないでそれを返すほうが自然? Stringを伸ばしていって最後にwrite!したほうがいい?
}
}
とすると
let mut list = List::new();
println!("{}", &list); // 表示結果 has no nodes
for i in &[1, 2, 3] {
list.push_back(i);
}
println!("{}", &list); // 表示結果 1 2 3
となります。