0

I am trying to implement a trait to get an inner struct from outer structs. I have many outer structs and would like to avoid code repetition. Do I need to implement the method individually or is there a better way to achieve this by composition? It does not compile but here is a minimal example of what I am trying to do:

struct Inner {
    id: i32,
}

struct Outer1 {
    inner: Inner,
    something: i32,
}

struct Outer2 {
    inner: Inner,
    something_different: String,
}

trait GetInner {
    fn id(&self) -> i32 {
        self.inner.id
    }
}

impl GetInner for Outer1 {}
impl GetInner for Outer2 {}

fn main() {
    let inner = Inner { id: 1 };
    let outer1 = Outer1 {
        inner: inner,
        something: 2,
    };

    outer.id()
}
error[E0425]: cannot find value `outer` in this scope
  --> src/main.rs:31:5
   |
31 |     outer.id()
   |     ^^^^^ help: a local variable with a similar name exists: `outer1`

error[E0609]: no field `inner` on type `&Self`
  --> src/main.rs:17:14
   |
15 | / trait GetInner {
16 | |     fn id(&self) -> i32 {
17 | |         self.inner.id
   | |              ^^^^^
18 | |     }
19 | | }
   | |_- type parameter 'Self' declared here
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Neotenic Primate
  • 313
  • 3
  • 13

1 Answers1

2

You can implement the trait with a declarative macro:

struct Inner {
    id: i32,
}

struct Outer1 {
    inner: Inner,
    something: i32,
}

struct Outer2 {
    inner: Inner,
    something_different: String,
}

trait GetInner {
    fn id(&self) -> i32;
}

macro_rules! get_inner_impl {
    ($($outer:ty)*) => ($(
        impl GetInner for $outer {
            fn id(&self) -> i32 {
                self.inner.id
            }
        }
    )*)
}

get_inner_impl! { Outer1 Outer2 }

fn foo(outer1: Outer1) {
    println!("{}", outer1.id());
}

fn bar(outer2: Outer2) {
    println!("{}", outer2.id());
}

fluzz
  • 36
  • 2