I have code similar to the following:
enum Value {
Bool(bool),
Int(i32),
Float(f32),
Str(String),
}
fn get_value(key: &str) -> Value {
// read value from file
match key {
"b" => Value::Bool(true),
"i" => Value::Int(666),
"f" => Value::Float(42.),
"s" => Value::Str("😈".to_string()),
_ => panic!("Key {} not found.", str),
}
}
fn convert<T>(e: &Value) -> T {
// what to put here?
}
fn query<T>(t: &str) -> T {
// … validation etc.
convert::<T>(&get_value(t))
}
fn main() {
let i = query::<i32>("i");
}
I.e. I need to query
some values from a text file. query
takes a type parameter and a string key parameter. It then returns the value associated to that key in the text file (if the type parameter and the type of the value don't match, simply panic!
). Value
and get_value
are from a library in the actual code.
However I'm facing a problem when trying to convert
a Value
instance to the type it holds. If I try to do it with a simple match
, I get
error: mismatched types: expected
T
, foundx
where x
is one of bool
/i32
/f32
/String
.
What is the right way to do this in Rust?
Here there is a possible solution:
enum Value {
Bool(bool),
Int(i32),
Float(f32),
Str(String),
}
fn get_value(key: &str) -> Value {
// read value from file
match key {
"b" => Value::Bool(true),
"i" => Value::Int(666),
"f" => Value::Float(42.),
"s" => Value::Str("😈".to_string()),
_ => panic!("Key {} not found.", key),
}
}
trait ConversionTrait {
type Output;
fn convert(v: &Value) -> Option<Self::Output> {
None
}
}
impl ConversionTrait for i32 {
type Output = i32;
fn convert(v: &Value) -> Option<Self::Output> {
match (*v) {
Value::Int(x) => Some(x),
_ => None
}
}
}
fn convert<T>(e: &Value) -> Option<T> where T : ConversionTrait<Output = T> {
T::convert(e)
}
fn query<T>(t: &str) -> Option<T> where T : ConversionTrait<Output = T> {
// … validation etc.
convert::<T>(&get_value(t))
}
fn main() {
let i = query::<i32>("i");
// let j = query::<f32>("i"); ConversionTrait not implemented
println!("{:?}", i);
}
First of all the convert
and query
methods could fail, so it's better they return an Option
which can be None
in case of failure.
Second, in Rust there is no generic specialization at the moment so a possible solution is to define a trait to do the conversion then implement the trait only for the types you want the conversion. (with generic specialization you would implement different version of the convert function)
Each implementation of the ConversionTrait
above should extract the proper value from the Value
object and return it.
I implemented only the i32
version for reference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With