素朴なOOPLの気持ちで書いてるとハマる話
経緯
経緯を簡略化したコードで書いていく。
元のコード
struct Context;
impl Context {
fn do_something(&mut self) {}
}
fn func(context: &mut Context) {
context.do_something();
}
実際はContext
はメンバ持ってたり、do_something()
も空実装ではないが省略。
次にContext
をトレイトにしたくなった。
trait Context {
fn do_something(&mut self);
}
struct ContextImpl;
impl Context for ContextImpl {
fn do_something(&mut self) {}
}
fn func(context: &mut Context) {
context.do_something();
}
特に問題は無い。
ここに、Hoge
トレイトを追加して、Context
に対して実装する。
trait Hoge {
fn hoge(&mut self);
}
impl<T: Context> Hoge for T {
fn hoge(&mut self) {
self.do_something();
}
}
fn func(context: &mut Context) {
context.do_something();
context.hoge();
}
コンパイルエラーになる
error[E0599]: no method named `hoge` found for type `&mut dyn Context` in the current scope
--> src/main.rs:23:13
|
23 | context.hoge();
| ^^^^
|
= note: the method `hoge` exists but the following trait bounds were not satisfied:
`&mut dyn Context : Hoge`
`dyn Context : Hoge`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `hoge`, perhaps you need to implement it:
candidate #1: `Hoge`
error: aborting due to previous error
何がいけなかったかと言うと、func()
の引数を&mut Context
のままにしておいたのがダメだった。
fn func<T: Context>(context: &mut T) {
context.do_something();
context.hoge();
}
これでコンパイルエラーはなくなる。