Generic Return Type. Again

There's a plenty of similar questins but I could not find a reasonable solution to my problem.

Ideally, I'd like to have a nice API like this:

let data = read_data::<Vec<f32>>()

Where read_data calls to ffi functions of different flavours, e.g

void getFloatAttributeData(..)
void getDoubleAttributeData(..)
void getIntAttributeData(..)
void getInt64AttributeData(..)

All these calls only differ by return type, I was hoping to utilize Rust generics somehow to make it nicer to use. I'm convinced that it's not possible, because it would require something like this:

fn read_data<T>(..) -> Vec<T> {
    // branch  based on type of T (Any::TypeID?) I think it's impossible.

I would be okay with adding an extra argument if it worked, but it doesn't either:

fn read_data<T>(ty: DataType) -> Vec<T> {
     match ty {
          Float => // call ffi::getFloatAttributeData(),
          Int => //call ffi::getIntAttributeData()

let data = read_data::<f32>(DataType::Float)

The only solution I'm currently using is returning an enum with a payload for each data type. I know it's idiomatic, but I just wanted to hear is this the only way?

You could have a trait like this:

// Don't worry about the `: Sized` part, it's just to reassure the compiler
// that you're not going to try to return a `Vec<[u8]>` or something.
trait ReadData: Sized {
    fn read_data() -> Vec<Self>;

and then impl it for each "flavor", like this:

impl ReadData for f32 {
    fn read_data() -> Vec<Self> {
        // FFI stuff goes here

impl ReadData for f64 {
    fn read_data() -> Vec<Self> {
        // more FFI stuff

// etc.

Then you'd invoke this as

let data: Vec<f32> = ReadData::read_data();

(type annotation required so the compiler knows which impl to use), or you could have a wrapper function that makes it look more like what you originally asked for.


Ah, perfect! Thank you so much.

1 Like

Alternatively, you can call like this:

// return type is inferred
let data = f32::read_data();
1 Like