Impl Trait for any struct with a specific field


#1

Is it possible to implement a Trait generically for any struct that contains a specified field name?

Something like:

impl<T> MyTrait for T
    where T.fieldname

#2

No, it’s not possible.

In general, structural typing is against Rust philosophy. Can you elaborate why you want to do this?


#3

What do you mean by “structural typing?”

I have bunch of structs that are similar and all need some common traits, but for which certain subsets will need additional traits.


#4

You can often fall back on macros. It’s not uncommon to see impl_foo! macros:

macro_rules! impl_foo {
    ($type:ty) => {
        impl Foo for $type {
            fn get_foo(&self) -> u8 { self.foo }
        }
    }
}

I’ve used this in the past when I was using the bitflags crate, which generates structs that all have a fn bits(&self) -> u8 method, but I wanted to write code that was generic over different bitflag types.


#5

In the sense of structural vs. nominal type systems, Rust follows the latter. Just having particular methods or fields is never enough to implement a trait. Even blanket declarations like impl<T> Foo for T only work if you can express type constraints that are sufficient to implement Foo abstractly.

Macros are ok if that set of structs is a fixed list. Another option is to compose those structs around a shared inner struct, then define accessor methods as needed to reach it, or perhaps a generic AsRef<Inner> so you can write foo.as_ref().do_common_thing().


#6
macro_rules! impl_foo {
    ($type:ty) => {
        impl Foo for $type {
            fn get_foo(&self) -> &str { self.foo }
        }
    }
}

impl_foo!(My_Struct); //=> "missing lifetime specifier: expected lifetime parameter"

impl_foo!(My_Struct<'a>); //=> "use of undeclared lifetime name `'a`: undeclared lifetime"

How would I circumvent this issue, or is it not possible?


#7

You’d pass the lifetime param as a separate token: example


#8

ah, brilliant, cheers.