How to initialize object with trait

Hi,

I've got code / structs :

pub struct Letter <T: DetailedLetter> {
   amount: usize,
   detail: T
}
impl <T: DetailedLetter> Letter <T> {..}

pub trait DetailedLetter {
   fn some_fun(&self, msg: &str) -> &str;
}

struct A; 
impl DetailedLetter for A {...}

pub struct AlphabetHolder < T: DetailedLetter > {
   letters: Option<Vec<Letter<T>>>,
   number: usize
}

impl <T: DetailedLetter > AlphabetHolder<T> {

    pub fn new (init_num: usize) -> Self {
       Self { letters: None  , 
               number: init_num
            }
    }
}

How to initialize object for AlphabetHolder in main function ?

fn main {
// I try this way but got error , (with dyn or without dyn) 
let mut alphabet_holder = AlphabetHolder::<dyn DetailedLetter>::new(50) ; 
.....
}

But I've got error :

^^^ function or associated item cannot be called on AlphabetHolder due to unsatisfied trait bounds
or

 AlphabetHolder::<DetailedLetter>::new(500);
   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time

Thanks in advance for hint/help .

You need to decide what T would be. It could be any type that implements DetailedLetter. So going by your code, you could do: AlphabetHolder::<A>::new().

1 Like

Your immediate problem is that dyn DetailedLetter is dynamically-sized, so it can't be stored by value.

But I suspect you don't actually want to store a dyn DetailedLetter, do you? A dyn Trait is a single, concrete type (dynamically backed by another type implementing the trait). It is not the same as generics. If you are trying to instantiate a generic type, you should either just let type inference figure out the substitution for the type parameter, or you should specify the correct concrete, static type in the turbofish. Instantiating a generic with an explicit dyn Trait is almost surely a result of misunderstanding how generics and traits work.

2 Likes

Hi , during initialization I don't want to decide which T would be. Maybe "A" struct which implements DetailedLetter , or maybe "B" , or "C" ... etc. How to solve it ?

The T must be fixed one way or the other. You can do it while calling new. Or you can let it be decided later when a separate function call is made (like you typically call Vec::new() and let the T of Vec<T> be inferred later on).
Alternatively, you can make T as Box<dyn DetailedLetter> if you want to store different types which all implement DetailedLetter.

2 Likes

Thanks for hint , but what if I have struct like this :

pub struct AlphabetHolder < T: DetailedLetter > {
   letter1: Option<Vec<Letter<T>>>,
   letter2: Option<Vec<Letter<T>>>,
   number: usize
}

And letter1 will hold struct A which implements DetailedLetter, and letter2 will hold struct B (B also implements DetailedLetter) ?

Thanks for another hint .

I can't figure out how to do it . Where should I inject Box ? In Letter struct or AlphabetHolder ? I'm stuck with it .

I've found solution :


pub struct Letter <T: DetailedLetter + ?Sized> {
   amount: usize,
   detail: T
}
impl <T: DetailedLetter> Letter <T> {..}

pub trait DetailedLetter {
   fn some_fun(&self, msg: &str) -> &str;
}

struct A; 
impl DetailedLetter for A {...}

pub struct AlphabetHolder  {
   letters: Option<Vec<Box<Letter<dyn DetailedLetter>>>>,
   number: usize
}

impl  AlphabetHolder {

    pub fn new (init_num: usize) -> Self {
       Self { letters: None  , 
               number: init_num
            }
    }
}

Now , I can initialize via :

let mut alphabet_holder = AlphabetHolder::new(50) ;