3

While trying to implement traits with generic arguments and access the fields of those generic arguments, I've encountered an error message saying that the arguments in question do not contain such fields.

Here's some example code that exhibits the issue:

pub struct Settings {
    pub time: String,
}

pub trait Foo {
    fn get<T>(t: T);
}

struct Bar;

impl Foo for Bar {
    fn get<Settings>(t: Settings) {
        let x = t.time;
    }
}

(Playground)

The error message given by the compiler is as follows:

error: no field `time` on type `Settings`

which makes little sense in the context. I expect that this is probably some misuse of generic traits on my part but the error message makes the question that.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Ameo
  • 2,307
  • 5
  • 21
  • 33

1 Answers1

5

Within the context of the method implimentation, Settings is a "generic type".

That is, what you've got there in your example, is the equivalent of this:

impl Foo for Bar {
    fn get<RandomWordHere>(t: RandomWordHere) {
        let x = t.time;
    }
}

Does the error make more sense now? Your generic type Settings is shadowing your actual type Settings.

Your method isn't very generic in this sense now anyway.. since you're saying "I want an actual instance of a Settings struct". Whereas you probably want "I want an instance of any type that has a time field".

Here is how you do the latter:

pub trait HasTime {
    fn get_time(&self) -> &String;
}

pub struct Settings {
    pub time: String
}

impl HasTime for Settings {
    fn get_time(&self) -> &String {
        &self.time
    }
}

pub struct OtherStruct;

pub trait Foo {
    fn get<T>(t: T) where T: HasTime;
}

struct Bar;

impl Foo for Bar {
    fn get<T>(t: T) where T: HasTime {
        let x = t.get_time();
    }
}

fn main() {
    Bar::get(Settings{time: "".into()}); // This is fine
    // Bar::get(OtherStruct{}); // This is an error.. it doesn't implement HasTime
}

Playground link

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138