Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to store a value in a struct through a trait?

Editor's note: This code example is from a version of Rust prior to 1.0 and is not syntactically valid Rust 1.0 code. Updated versions of this code produce different errors, but the answers still contain valuable information.

I tried this with and without Box, with and without lifetimes:

trait TraitToImpl {
    fn do_something(self, val: i32);
}

struct Cont {
    value: i32,
}

impl TraitToImpl for Cont {
    fn do_something(self, val: i32) {
        println!("{}", val);
    }
}

struct StoreTrait<'a> {
    field: Box<TraitToImpl + 'a>,
}

fn main() {
    let cont = Box::new(Cont { value: 12 }) as Box<TraitToImpl>;
    let a = StoreTrait { field: cont };
    a.field.do_something(123);
}

All I get is this error:

error: cannot convert to a trait object because trait `TraitToImpl` is not object-safe

like image 336
Sergey Zalizko Avatar asked Nov 19 '14 15:11

Sergey Zalizko


1 Answers

The problem is, as the error message says, that the trait TraitToImpl is not object safe. That is, it is not safe to use that particular trait through a reference (i.e. &TraitToImpl or Box<TraitToImpl>.

Specifically, the do_something method takes self by value. Consider: how does the compiler call this method on a Cont that's been placed in a Box<TraitToImpl>? It has to copy the value into an argument of type Cont (which is what the impl expects), but this call has to work for any type of any size that might implement TraitToImpl!

Practical upshot: if you have a trait which contains by-value self, or generics, it cannot be used via a reference. At the point the call happens, the compiler no longer has enough information to actually generate the necessary code.

Maybe try taking &self instead? :)

like image 146
DK. Avatar answered Nov 16 '22 15:11

DK.