zman
zman

Reputation: 223

Rust returning enum as generic type

I'm attempting to create a struct that holds a collection of Nodes. In order to limit the type, each of these Nodes can hold the value is of the enum type NodeVal.

I can then add accessor functions to the Container struct to get and set the values. However, rather than adding a get_node_f64, get_node_i64, etc, I'm attempting to make a generic function that accepts a type that implements the Num trait.

This does not work seemingly because the val property of Node is NodeVal rather than T. However if I make it T it will be able to be any type, which I want to avoid.

Is there any way to achieve what I want to do or am I structuring this the wrong way?

use std::collections::HashMap;
use num_traits::Num;

pub enum NodeVal {
    Str(String),
    F64(f64),
    Uint64(u64),
    Int64(i64),
}

pub struct Node {
    id: i32,
    val: NodeVal
}

pub struct Container {
    nodes: HashMap<i32, Node>
}

impl Container {
    pub fn new() -> Self {
        Container {
            nodes: HashMap::new()
        }
    }

    pub fn get_node_str(&self, key: &i32) -> Option<String> {
        match self.nodes.get(key) {
            Some(r) => match &r.val {
                NodeVal::Str(x) => Some(x.to_string()),
                _ => None
            },
            None => None
        }
    }

    // Does not compile
    pub fn get_node_num<T: num_traits::Num>(&self, key: &i32) -> Option<T> {
        match self.nodes.get(key) {
            Some(r) => match &r.val {
                NodeVal::F64(x) | NodeVal::Uint64(x) | NodeVal::Int64(x) => Some(*x),
                _ => None
            },
            None => None
        }
    }
}

Upvotes: 1

Views: 1605

Answers (1)

Masklinn
Masklinn

Reputation: 42207

This does not work seemingly because the val property of Node is NodeVal rather than T. However if I make it T it will be able to be any type, which I want to avoid.

What I get is that it doesn't work because x is of a different type in the three variants you're matching, which doesn't make any sense to Rust, it complains that the x in F64 is an f64, the x in Uint64 is an u64 and the x in Int64 is an i64, therefore the type of x makes no sense (it has three incompatible types it can't reconcile).

Your use of trait bounds is also incorrect, trait bounds are a way for the caller to specify types, but get_node_num does not consider that for a single second, it doesn't care what the caller wants.

Plus the reasoning doesn't make sense:

However if I make it T it will be able to be any type, which I want to avoid.

get_node_num decides what the return type is, T is completely useless. get_node_num also can't work, because you can't return a "f64 or u64 or i64" in Rust, except by creating a new enum which stores these alternatives.

Upvotes: 2

Related Questions