Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I access struct fields within default method definitions of traits? [duplicate]

Tags:

rust

traits

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,
        )
    }
}
like image 863
d8aninja Avatar asked Jun 07 '26 06:06

d8aninja


2 Answers

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?

like image 60
Sebastian Redl Avatar answered Jun 10 '26 13:06

Sebastian Redl


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...)

like image 37
d8aninja Avatar answered Jun 10 '26 13:06

d8aninja