How to have dynamic Box<dyn Trait<T,S>>?

Viewed 391

I had list of transactions of type T and S,at run time I want to fetch its details . How to have traits for multiple generics types for struct Code i tried is mentioned below :-

use std::fmt::Debug;
use std::any::Any;


#[derive(Debug)]
struct TransactionSet<T,S>{
    pub name: String,
    pub key:T,
    pub value:S

}

trait Details<T,S>{
    fn get_details(&self);

    fn get_key(&self)->&T;

    fn get_value(&self)->&S;
}

impl<T: Debug, S: Debug> Details<T,S> for TransactionSet<T, S> {
    fn get_details(&self) {
        println!("{:?} {:?} {:?}",self.name.to_string(),&self.key,&self.value)
    }
    fn get_key(&self)->&T {
        &self.key
    }

    fn get_value(&self)->&S {
        &self.value
    }

}



fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}

fn get<T: Any>(value: Box<dyn Any>) -> T {
    let pv = value.downcast().expect("The pointed-to value must be of type T");
    *pv
}



fn main() {
    //let mut vec: Vec<Box<dyn NewTrait<T:Debug,S:Debug>>> = Vec::new(); //Not working
    //  let mut vec: Vec<Box<dyn Details<T: Debug,S: Debug>>> = Vec::new();//Cannot use Details Trait
    let  vec: Vec<Box<dyn Details<_,_>>> = Vec::new();//Cannot use Details Trait

    let a1:TransactionSet<String,String> = TransactionSet { name: String::from("Test1"), key: String::from("name"), value: String::from("vinay") };
    let a2:TransactionSet<String,i32> = TransactionSet { name: String::from("Test2"), key: String::from("age"), value: 32_i32 };
    let a3 = TransactionSet { name: String::from("Test3"), key: 1_i32, value: 10_u64 };
    let a4 = TransactionSet { name: String::from("Test4"), key: String::from("isEligibleToVote"), value: true };

    //let a2 = ABC::new( String::from("Test2"), String::from("company"),  String::from("supra"));;

    vec.push(Box::<TransactionSet<String,String>>::new(a1));
    vec.push(Box::<TransactionSet<String,i32>>::new(a2));
    vec.push(Box::new(a3));
    vec.push(Box::new(a4));
    for v in vec.iter() {
        v.get_details();
        //  print_type_of(v);

        println!("Key : {:?}", v.get_key());
        println!("Value : {:?}", v.get_value());
    }

}

Is there any other way I can resolve this ? Like Vec<Box<dyn Details<?Unknown,?Unknown>>> if i remove generic type for trait Details,I cannot write getter for it

Playground Link

1 Answers

You need to use dyn in order to abstrat to the trait you need.

First step is to add types to your trait, it do not need to be generic:

trait Details {
    type Key;
    type Value;
    fn get_details(&self);

    fn get_key(&self) -> &Self::Key;

    fn get_value(&self) -> &Self::Value;
}

Then you can implement the trait over some generic TransactionSet where bot T and S implement Debug:

impl Details for TransactionSet<Box<dyn Debug>, Box<dyn Debug>> {
    type Key = Box<dyn Debug>;
    type Value = Box<dyn Debug>;
    fn get_details(&self) {
        println!(
            "{:?} {:?} {:?}",
            self.name.to_string(),
            &self.key,
            &self.value
        )
    }
    fn get_key(&self) -> &Self::Key {
        &self.key
    }

    fn get_value(&self) -> &Self::Value {
        &self.value
    }
}

Notice the type of your TransactionSet is of TransactionSet<Box<dyn Debug>, Box<dyn Debug>>.

Here is a full working example:

use std::any::Any;
use std::fmt::Debug;

#[derive(Debug)]
struct TransactionSet<T, S> {
    pub name: String,
    pub key: T,
    pub value: S,
}

trait Details {
    type Key;
    type Value;
    fn get_details(&self);

    fn get_key(&self) -> &Self::Key;

    fn get_value(&self) -> &Self::Value;
}

impl Details for TransactionSet<Box<dyn Debug>, Box<dyn Debug>> {
    type Key = Box<dyn Debug>;
    type Value = Box<dyn Debug>;
    fn get_details(&self) {
        println!(
            "{:?} {:?} {:?}",
            self.name.to_string(),
            &self.key,
            &self.value
        )
    }
    fn get_key(&self) -> &Self::Key {
        &self.key
    }

    fn get_value(&self) -> &Self::Value {
        &self.value
    }
}

fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}

fn get<T: Any>(value: Box<dyn Any>) -> T {
    let pv = value
        .downcast()
        .expect("The pointed-to value must be of type T");
    *pv
}

fn main() {
    let mut vec: Vec<Box<dyn Details<Key = _, Value = _>>> = Vec::new(); //Cannot use Details Trait

    let a1: TransactionSet<Box<dyn Debug>, Box<dyn Debug>> = TransactionSet {
        name: String::from("Test1"),
        key: Box::new(String::from("name")),
        value: Box::new(String::from("vinay")),
    };
    let a2: TransactionSet<Box<dyn Debug>, Box<dyn Debug>> = TransactionSet {
        name: String::from("Test2"),
        key: Box::new(String::from("age")),
        value: Box::new(32_i32),
    };
    // let a3 = TransactionSet { name: String::from("Test3"), key: 1_i32, value: 10_u64 };
    // let a4 = TransactionSet { name: String::from("Test4"), key: String::from("isEligibleToVote"), value: true };

    vec.push(Box::<TransactionSet<Box<dyn Debug>, Box<dyn Debug>>>::new(
        a1,
    ));
    vec.push(Box::<TransactionSet<Box<dyn Debug>, Box<dyn Debug>>>::new(a2));
    // vec.push(Box::new(a3));
    // vec.push(Box::new(a4));
    for v in vec.iter() {
        v.get_details();
        //  print_type_of(v);

        println!("Key : {:?}", v.get_key());
        println!("Value : {:?}", v.get_value());
    }
}


Playground

Related