Get type from vec of generic struct?

Hello,

I wrote the bellow code.
My intention is to store a vec of generic struct (Metric) and retrieve each item afterwards. If possible with the original type they were created with.

Below code works fine. But I would like the get_mes() method to return T from Metric field mes and not a String.

use std::fmt::Debug;

#[derive(Debug)]
struct Metric<T> {
    name: String,
    mes: T,
}

trait Measure {
    fn get_name(&self) -> String;
    fn get_mes(&self) -> String;
}

impl Measure for Metric<usize> {
    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn get_mes(&self) -> String {
        self.mes.to_string()
    }
}

impl Measure for Metric<f32> {
    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn get_mes(&self) -> String {
        self.mes.to_string()
    }
}

impl Debug for dyn Measure {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "Metric{{name:{}, mes:{}}}", self.get_name(),self.get_mes())
    }
}


fn main() {
    let mut data: Vec<Box<dyn Measure>> = Vec::new();

    data.push(Box::new(Metric {
        name: String::from("titi"),
        mes: 12,
    }));
    data.push(Box::new(Metric {
        name: String::from("toto"),
        mes: 0.2,
    }));

    println!("{:?}", data[0].get_mes());
    println!("{:?}", data);
}

So I changed my code to this one : Rust Playground

And to be honest I don't know how to get out of these errors.
I have the feelings that it is not possible to return the original T type. Can you confirm ?

Is there a way to achieve what I would like to do ?

1 Like

It is not possible to automatically implement Debug for all types that implement Measure because that would let you implement Debug on a foreign type by implementing Measure for that foreign type.

Hi Alice,

Thanks for your answer.
Same question if I don't implement Debug ? Is it possible to have get_mes() to return T ?

How about this?

trait Measure<T> {
    fn get_name(&self) -> String;
    fn get_mes(&self) -> &T;
}

impl<T> Measure<T> for Metric<T> {
    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn get_mes(&self) -> &T {
        &self.mes
    }
}

Unfortunately, I need to define T (e.g. usize) and then I can not store Metrics using mes from other types unless if I'm wrong.
Pushing the second metrics will end up with:

error[E0277]: the trait bound `Metric<{float}>: Measure<usize>` is not satisfied
  --> src/main.rs:31:16
   |
31 |        data.push(Box::new(Metric {
   |  ________________^
32 | |         name: String::from("toto"),
33 | |          mes: 0.2,
34 | |      }));
   | |_______^ the trait `Measure<usize>` is not implemented for `Metric<{float}>`
   |
   = help: the following implementations were found:
             <Metric<T> as Measure<T>>
   = note: required for the cast to the object type `dyn Measure<usize>`
use std::fmt::Debug;

#[derive(Debug)]
struct Metric<T> {
    name: String,
    mes: T,
}

trait Measure<T> {
    fn get_name(&self) -> String;
    fn get_mes(&self) -> &T;
}

impl<T> Measure<T> for Metric<T> {
    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn get_mes(&self) -> &T {
        &self.mes
    }
}

fn main() {
    let mut data: Vec<Box<dyn Measure<usize>>> = Vec::new();

    data.push(Box::new(Metric {
        name: String::from("titi"),
        mes: 12,
    }));
// Uncomment to see error
//     data.push(Box::new(Metric {
//         name: String::from("toto"),
//         mes: 0.2,
//     }));

    println!("{:?}", data[0].get_mes());
}

Given a dyn SomeTypeOfMeasure that you can call methods on, the methods must be able to be type checked. So for example, method get_mes(&self) -> T must have a concrete type for the T. Consider this:

fn f(m: &dyn SomeTypeOfMeasure) {
    // Compiler needs to type check this with only the constraints in the declaration
    // Namely: `*m` is a `dyn SomeTypeOfMeasure`
    let x: usize = m.get_mes();
}

So whether you have Measure or Measure<T> or Measure<AsssociatedType = T>, the T is going to have to be concrete for any dyn [...].

You may need to be less generic by deciding what the full set of possible types for get_mes are and returning an enum, or picking a "good enough for anyone" type and having that be the return type of get_mes, etc.

You can keep being generic if you do something like this:

// Whatever trait is sufficient should take the place of `Display`
fn get_mes(&self) -> Box<dyn Display>;

Which works because Box<dyn Trait> is a concrete type. But you won't be getting the original types back out.

Thank you @quinedot.

To sumup (Please let me know if I'm wrong) :

Which works because Box<dyn Trait> is a concrete type. But you won't be getting the original types back out.

This is my first code at the top of this thread.
vec can store different generic structs but the original type can not be back out.

So whether you have Measure or Measure<T> or Measure<AsssociatedType = T> , the T is going to have to be concrete for any dyn [...] .

Is the code following @alice answer.
vec can store identical structs with a concrete type coming from a generic one

Looks like a good tradeoff.

struct Metric {
    name: String,
    mes: Mestype,
}


enum Mestype{
    Float(f64),
    Int(usize),
}


fn main() {
    let mut data: Vec<Metric> = Vec::new();

    data.push(Metric {
        name: String::from("titi"),
        mes: Mestype::Int(12),
    });
     data.push(Metric {
        name: String::from("toto"),
         mes: Mestype::Float(0.2),
     });

    println!("{:?}", data[0].name);
    match data[0].mes{
        Mestype::Float(x) => println!("{}",x),
        Mestype::Int(x) => println!("{}",x)
    }
}