1

Consider the following Rust code

trait Trait {
    fn show_name(&self) {}
}

struct Foo {
    name: String,
    things_and_stuff: usize,
}

impl Trait for Foo {
    fn show_name(&self) {
        println!("{}", self.name);
    }
}

struct Bar {
    name: String,
    other_field: i32,
}

impl Trait for Bar {
    fn show_name(&self) {
        println!("{}", self.name);
    }
}

The two show_name functions have exactly the same code. It would be convenient if I could put that method as a default method on Trait, but that's not possible because traits cannot access struct fields.

We could declare a get_name(&self) -> &str method on Trait and implement it on Foo and Bar, but that doesn't fix the problem of having duplicated code because both implementations of get_name will be the same.

It would be nice to avoid the code duplication. Another question has already asked if field access is possible in traits, and the answer was basically "no". However, I found a comment in the rust-internals forum suggesting that it's already possible. Here's the code:

struct Fields {
    name: String,
}

trait Trait: BorrowMut<Fields> {
    // methods go here
}

impl<T> Trait for T where T: BorrowMut<Fields> {}

Presumably there's a way to make a type T be BorrowMut<Fields> and use that to allow Trait to access Fields's fields, but so far I'm not sure how that would work.

How is the code snippet shown above supposed to solve the problem of getting field access in traits?


I know there are discussions of adding field access in traits to the language (rust-internals, RFC, another RFC), but I'd like to know what's possible now.

DanielSank
  • 3,303
  • 3
  • 24
  • 42
  • @Shepmaster I'd like to point out that the edited title contains words that may not be familiar to those who stand to benefit from this post. – DanielSank Nov 26 '18 at 17:06
  • Which ones? While it's useful to have wide question titles for searching purposes, following that to the logical end results in "code doesn't work, why"-esque titles. The current title has all of the same words that your original title had, but now clearly distinguishes it from the existing question. If people search for "access struct fields in a trait default method" and don't click on a result with some extra words, there doesn't seem to be a lot of help we can give them. – Shepmaster Nov 26 '18 at 17:10
  • @Shepmaster I didn't say the new title was worse. – DanielSank Nov 26 '18 at 17:11

1 Answers1

2

the answer was basically "no"

The answer actually says (emphasis mine):

A default implementation can only use methods that are defined on the trait or in a super trait.

That's what your snippet does:

trait Trait: BorrowMut<Fields>

To make it work, follow the advice from the post you are referencing:

all types which choose to implement BorrowMut<Foo>

Thus, you need to implement the trait for each of your types. I switched to Borrow because you don't need mutability here:

use std::borrow::Borrow;

struct Fields {
    name: String,
}

trait Trait: Borrow<Fields> {
    fn show_name(&self) {
        let fields: &Fields = self.borrow();
        println!("{}", fields.name);
    }
}

struct Foo {
    fields: Fields,
    things_and_stuff: usize,
}

impl Borrow<Fields> for Foo {
    fn borrow(&self) -> &Fields {
        &self.fields
    }
}

struct Bar {
    fields: Fields,
    other_field: i32,
}

impl Borrow<Fields> for Bar {
    fn borrow(&self) -> &Fields {
        &self.fields
    }
}

impl<T> Trait for T where T: Borrow<Fields> {}

I'm almost certain you won't like this solution because it

doesn't fix the problem of having duplicated code because both implementations [...] will be the same

You may prefer to write a macro if your goal is to reduce the number of duplicate characters in your code.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366