2026-08-25
formatter_dyn.rs
trait Formatter {
fn format<T: std::fmt::Display>(&self, value: T) -> String;
}
struct Prefixed {
prefix: String,
}
impl Formatter for Prefixed {
fn format<T: std::fmt::Display>(&self, value: T) -> String {
format!("{}{}", self.prefix, value)
}
}
fn main() {
let f: Box<dyn Formatter> = Box::new(Prefixed {
prefix: "> ".to_string(),
});
println!("{}", f.format(42));
}
このコードはコンパイルできません。何が問題で、どう直せばよいでしょうか?
Answer
formatがジェネリック型パラメータTを持つメソッドなので、Formatterはオブジェクト安全(dyn互換)ではありません。ジェネリックメソッドは呼ばれる型ごとに別々のコードを生成するので、実行時にただ1つのエントリで済む仮想関数テーブルには載せられないのです。Box<dyn Formatter>を作ろうとした時点でコンパイルエラーになります。ジェネリック引数の代わりにトレイトオブジェクト&dyn Displayを受け取るようにすれば、format自体が単相な(ジェネリックでない)メソッドになり、トレイトはdyn互換になります:
use std::fmt::Display;
trait Formatter {
fn format(&self, value: &dyn Display) -> String;
}
impl Formatter for Prefixed {
fn format(&self, value: &dyn Display) -> String {
format!("{}{}", self.prefix, value)
}
}
呼び出し側もf.format(&42)のように参照で渡すよう直します。