Why trait can not implement variable?

Why trait can not implement variable?

Below example we can add / attach / implement function or method to struct but why can not implement variable to the struct?

trait SomeTrait {
    fn fn_name () -> u32;
}

impl SomeTrait for SomeStruct {
    fn fn_name () {
        ...
    }
}

This works for me:

struct SomeStruct { /* … */ }

trait SomeTrait {
    fn fn_name(&self) -> u32;
}

impl SomeTrait for SomeStruct {
    fn fn_name(&self) -> u32 {
        todo!()
    }
}

(Playground)

You probably missed the -> u32 at the impl?

Also note that methods usually work on &self or &mut self, as otherwise it's only an associated function (and not a method).

2 Likes

It is unclear what is being asked here. Variables are not things to be "implemented". You can implement a trait for a type, but that's it.

If you are having trouble expressing yourself in English, please seek help from someone who can formulate your question more clearly.

5 Likes

What @krishnatorque possibly meant is a method which serves as a getter for a variable field (of type u32) of the struct.

What may also help is to provide an error message, or a small example that can be compiled and which reproduces the error. Like this:

struct SomeStruct { /* … */ }

trait SomeTrait {
    fn fn_name () -> u32;
}

impl SomeTrait for SomeStruct {
    fn fn_name () {
        todo!()
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0053]: method `fn_name` has an incompatible type for trait
 --> src/lib.rs:8:19
  |
8 |     fn fn_name () {
  |                   ^ expected `u32`, found `()`
  |
note: type in trait
 --> src/lib.rs:4:22
  |
4 |     fn fn_name () -> u32;
  |                      ^^^
  = note: expected fn pointer `fn() -> u32`
             found fn pointer `fn()`
help: change the output type to match the trait
  |
8 |     fn fn_name () -> u32 {
  |                   ++++++

For more information about this error, try `rustc --explain E0053`.
error: could not compile `playground` due to previous error

This error also shows you how to solve the problem: add the missing -> u32 to match the trait.

P.S.: Note that I used the todo! macro for creating the example, which I find quite helpful when providing examples or testing whether some code compiles.

2 Likes

wow great
that was rude but thanks for your reply

Not everyone is a native English speaker, so it's normal that grammar or vocabulary can be messed up. In my opinion that's not a problem. My native language is German.

Feel free to ask for help here, even if your English isn't 100% correct. It can help, however, to try to be as precise as possible.

Getting the terminology right can also be tricky, even for English speakers. For example, I made a mistake here:

Structs have fields and methods, not variables (but I made that mistake as well and actually had to look that up in the reference).

P.S.: Did your question get answered?

P.P.S.: Of course traits have methods too. But you can also implement methods directly on the struct. Either is possible.

3 Likes

@jbe Thanks

where we implement a trait, its method attached to the struct e.g.

trait Trait { ... }

impl Trait for Struct {
    fn_name { .. }
}

now fn_name method is attached to the struct Struct and can be access from Struct.
Ofcource if we import / use it.

But what about fields. e.g.

trait Trait { 
    new_field: u32
}

impl Trait for Struct {
    fn_name { .. }
}

now we will get error & the new_field can not be access from struct Struct.

Hope that make sense & clear my question.

If your question is whether fields can be defined in traits, then the answer is no.

2 Likes

In forums where many people are not using their first language, it is best to assume that people are not being rude.

3 Likes

Traits can contain:

  • functions/methods
  • associated types
  • constants

If you want a trait to provide access to a field, you need to use getters and setters like this:

struct SomeStruct {
    foo: u32, // you need to write this manually!
}

struct SomeOtherStruct {
    foo: u32, // you need to write this manually!
    _bar: String,
}

trait SomeTrait {
    fn foo(&self) -> u32;
    fn set_foo(&mut self, value: u32);
}

impl SomeTrait for SomeStruct {
    fn foo(&self) -> u32 {
        self.foo
    }
    fn set_foo(&mut self, value: u32) {
        self.foo = value
    }
}

impl SomeTrait for SomeOtherStruct {
    fn foo(&self) -> u32 {
        self.foo
    }
    fn set_foo(&mut self, value: u32) {
        self.foo = value
    }
}

fn some_generic_function<T: SomeTrait>(mut arg: T) {
    println!("{}", arg.foo());
    arg.set_foo(10);
    println!("{}", arg.foo());
}

fn main() {
    let a = SomeStruct { foo: 5 };
    some_generic_function(a);
    let b = SomeOtherStruct { foo: 6, _bar: "Dummy".to_string() };
    some_generic_function(b);
}

(Playground)

Output:

5
10
6
10


P.S.: In cases where the field is a non-Copy type, e.g. String, the type signature may look slightly different. In that case, the getter returns a reference usually, but may depend on the use case. For example:

struct SomeOtherStruct {
    _foo: u32,
    bar: String,
}

trait SomeOtherTrait {
    fn bar(&self) -> &str;
    fn set_bar(&mut self, value: String);
}

impl SomeOtherTrait for SomeOtherStruct {
    fn bar(&self) -> &str {
        &self.bar // note the `&` here!
    }
    fn set_bar(&mut self, value: String) {
        self.bar = value;
    }
}

(Playground)

Output:

Hello
New string

1 Like

@H2CO3 Thanks

@jbe Thanks

When you do that Rust, basically, replaces s.fn_name with Trait::fn_name(s) (there are some complications, but the idea is like that).

Note how this doesn't change anything in the Struct itself. And when program is execute there are no “attachment” between trait and Struct. It all happens during compile time.

What do you propose field access to rewrite into?

2 Likes

The corresponding section in the Rust reference is: 6.11. Traits.

2 Likes