Итак, следуя онлайн-учебнику, я хотел расширить функциональность черты Canine, используя поле name из структуры, в которой реализована черта:
struct Animal {
name: String,
}
impl Animal {
fn eat(&self) {
println!("{} is eating", &self.name)
}
fn breathe(&self) {
println!("{} is breathing", &self.name)
}
}
trait Canine {
fn bark(&self) {
println!("Woof woof!");
}
fn run(&self) {
println!("{} is running.", &self.name);
}
}
impl Canine for Animal {}
fn main() {
let rover: Animal = Animal {
name: String::from("Rover")
};
// rover can do these as an animal
rover.eat();
rover.breathe();
// rover can additionally do these as a canine
rover.bark();
rover.run();
}
Этот код работает, за исключением одного компонента: метода run() в трейте Canine. Ошибка компилятора:
error[E0609]: no field `name` on type `&Self`
--> src/main.rs:21:42
|
15 | trait Canine {
| ------------ type parameter 'Self' declared here
...
21 | println!("{} is running.", &self.name);
| ^^^^
For more information about this error, try `rustc --explain E0609`.
Почему я могу использовать &self.name в определениях методов базовой реализации для структуры Animal, но не в трейте Canine? Каким будет правильный способ сделать это?
Заранее спасибо!

Черта Canine должна определять функции, но не реализации, а затем вы помещаете эти реализации в блок impl Canine for Animal.
trait Canine {
fn bark(&self);
fn run(&self);
}
impl Canine for Animal {
fn bark(&self) {
println!("Woof woof!");
}
fn run(&self) {
println!("{} is running.", &self.name);
}
}
Теперь компилятор знает, что такое self.name, так как это явно Animal. В исходном коде неизвестно, что это такое, так как это просто трейт без контекста.
Альтернативой является определение какого-либо другого признака, такого как Named, который можно использовать в качестве зависимости:
trait Named {
fn name(&self) -> &str;
}
trait Canine : Named {
fn run(&self) {
println!("{} is running.", self.name());
}
}
Спасибо! Это очень полезно. Мне особенно нравится альтернатива, допускающая реализацию по умолчанию. т. е. нет собачьих растений, есть только животные, поэтому я хочу, чтобы было ясно, что Canine когда-либо будет реализован только для структур Animal.
Rust сильно зависит от композиции, поэтому вам может понадобиться основа Creature, для которой вы затем impl Animal и т. д.
Имеет смысл. Также похоже, что есть как когерентность, так и запечатанные черты, которые являются другими подходами к этому шаблону: api-рекомендации/…
Вы не можете. Вы должны определить метод получения.