0

I have the following code, that I think is pretty self-explanatory. The problem I'm facing is in the render function:

fn render(&self) -> &'static str {
    self.view.value
}

Where the compiler complains:

attempted access of field `view` on type `&Self`, but no field with that name was found`

Full code:

struct View1 {
    value: &'static str,
}

struct View2 {
    value: &'static str,
    another_value: &'static str,
}

struct Pattern<T> {
    view: T,
}

trait Renderable {
    fn render(&self) -> &'static str {
        self.view.value
    }
}

impl <T> Renderable for Pattern <T> {}

fn patterns() -> Vec<Box<Renderable>> {
    vec![
        Box::new(Pattern { view: View1 { value: "x" } }),
        Box::new(Pattern { view: View1 { value: "y" } }),
    ]
}

fn main() {
    let p = patterns();

    for x in p.iter() {
        println!("{}", x.render());
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
caio
  • 1,949
  • 16
  • 20

1 Answers1

1

Yes, traits do not have access to the fields of their implementors. You need to provide accessor methods. These are small and should be optimized away:

trait View {
    fn value(&self) -> &'static str;
}

struct View1 {
    value: &'static str,
}

impl View for View1 {
    fn value(&self) -> &'static str { self.value }
}

struct View2 {
    value: &'static str,
    another_value: &'static str,
}

impl View for View2 {
    fn value(&self) -> &'static str { self.value }
}

trait Renderable {
    fn view(&self) -> &View;

    fn render(&self) -> &'static str {
        self.view().value()
    }
}

struct Pattern<T>
    where T: View
{
    view: T,
}

impl<T> Renderable for Pattern<T>
    where T: View
{
    fn view(&self) -> &View {
        &self.view
    }
}

fn patterns() -> Vec<Box<Renderable>> {
    vec![
        Box::new(Pattern { view: View1 { value: "x" } }),
        Box::new(Pattern { view: View2 { value: "y", another_value: "z" } }),
    ]
}

fn main() {
    let p = patterns();

    for x in p.iter() {
        println!("{}", x.render());
    }
}

Basically, traits are contracts that objects must adhere to, and the language of those contracts is the function names, the argument types, and the return types. If a trait needs to be able to get a view or a value, then that needs to be a part of the trait.

Note that implementations of traits do have access to the fields of the struct they are implementing the trait on. Since the implementation is specialized for one type, that guarantees that you have access to the appropriate fields.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • This is great. Isn't it possible to make a default implementation of the `value()` methods? Having to repeat them over and over again looks cumbersome. – caio Apr 11 '15 at 22:52
  • 1
    @caio there's always macros! ^_^. However, if you actually find yourself repeating code over and over, perhaps you can extract the common code out into a new struct and then embed that struct where you extracted it from. Otherwise, you are going to *want* different implementations, so a default wouldn't be useful. You may be interested in [this question](http://stackoverflow.com/q/29256519/155423) that asked about the case in the middle of those two extremes. – Shepmaster Apr 11 '15 at 22:57