I have a 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 the following code:
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 the generic type for trait Details
, I cannot write a getter for it.
You need to use dyn
in order to abstract to the trait you need.
First step is to add types to your trait, it does 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 both 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
}
}
Note that 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());
}
}