Reputation: 223
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
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