I see some related questions (like this and this) but I'm hoping that my use case for default methods is unique enough to ask a slightly different question. The following minimal example works and outputs "Sheriff Ted" shot "Billy the Kid"!:
#[derive(Debug)]
struct Actor {
name: String,
}
fn main() {
let cop = Actor {
name: String::from("Sheriff Ted"),
};
let robber = Actor {
name: String::from("Billy the Kid")
};
println!("{:?} shot {:?}!", cop.name, robber.name); // without the trait. with:
// cop.shoot(&robber);
}
//pub trait Shoot {
// fn shoot(&self, other: &Actor) {
// println!("\n{:?} shot {:?}!",
// &self.name,
// &other.name,
// )
// }
//}
//
//impl Shoot for Actor {}
As you can see, I want impart the Shoot implementation and the shoot method it contains on the Actor struct. When I uncomment the Shoot trait, its implementation on Actor, and the call cop.shoot(&robber), I get the error message related questions have gotten, as well: error[E0609]: no field 'name' on type '&Self'.
My first thought was to specify &self: Actor in the default method's signature, but that yields the delimiter error, so isn't syntactically valid.
I think this question is unique because the other questions seem to misunderstand how the generics they specify are shadowing their intended types, and in my case I'm not understanding why I can't access fields within the structs on which I am trying to implement a default method.
This works for cases when only Actors need to shoot, but I am looking for a way to apply this behavior (right now, just printlning) across multiple types.
impl Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
)
}
}
You are not trying to implement a default method on any structs; you are implementing it for the trait. Therefore you can't access any fields on any structs; you can only access what the trait demands.
A default implementation of a trait methods means that any type that implements the non-defaulted methods of the trait can use the default method, no matter what it looks like otherwise. But you expect that the implementing type has a name field in addition to what the trait demands (it demands nothing, by the way).
This is simply not a valid assumption.
I wonder why you're using a trait here at all. If you are okay with requiring self to be Actor in the shoot method, why is it a method of a trait? Why isn't it an inherent method of the Actor struct without any traits?
After having read Sebastian's response, I think the "answer" is: you can't name struct fields in traits' default methods because you don't know what fields a struct may have until the implementation of the trait. So you'd define an (abstract?) method signature, and then make it concrete when it's implemented. In my case, this works:
trait Shoot {
fn shoot(&self, other: &Actor);
}
impl Shoot for Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
);
}
}
Still interested to know if I can constrain a trait to be applied only to structs with certain fields and if this is different than "trait bounds". (It is, I think...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With