Generics 从泛型方法中的联合样式枚举获取活动值

Generics 从泛型方法中的联合样式枚举获取活动值,generics,enums,type-conversion,rust,Generics,Enums,Type Conversion,Rust,我有类似以下代码: 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),

我有类似以下代码:

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("The short answer is that you can't. Check out your function prototype:

fn convert<T>(e: &Value) -> T
枚举值{
布尔(布尔),
Int(i32),
浮动(f32),
Str(字符串),
}
fn获取_值(键:&str)->值{
//从文件中读取值
匹配键{
“b”=>Value::Bool(真),
“i”=>Value::Int(666),
“f”=>Value::Float(42.),

“s”=>Value::Str(“简而言之,您不能。请查看您的函数原型:

fn parse<F>(&self) -> Result<F, F::Err> 
    where F: FromStr
{
    FromStr::from_str(self)
}
是这里真正的英雄,许多类型都实现了它。任何实现
FromStr
的类型都可以与
parse
一起使用

我相信您可以在您的案例中使用
FromStr
,因为您的代码没有任何意义。^\u^您的示例代码:

let id: i32 = row.get(0);
let name: String = row.get(1);
我相信您可以借助str的
添加一些样板:

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("Andrea P's answer was really helpful. I adapted it a little and also made a macro to avoid code duplication in the 
impl Convert
s. Here's the result just in case anyone is interested:

trait Convert : Sized {
    fn convert(Value) -> Option<Self>;
}

macro_rules! impl_convert {
    ($t:ty, $id:ident) => (
        impl Convert for $t {
            fn convert(v: Value) -> Option<$t> {
                match v {
                    Value::$id(x) => Some(x),
                    _ => None,
                }
            }
        }
    )
}

impl_convert!(bool, Bool);
impl_convert!(i32, Int);
impl_convert!(f32, Float);
impl_convert!(String, Str);

fn query<T: Convert>(t: &str) -> T {
    // … validation etc.
    match T::convert(get_value(t)) {
        Some(x) => x,
        None => panic!("`{}` has an incorrect type", t),
    }
}
使用std::collections::HashMap;
使用std::str::FromStr;
结构配置文件{
原始:HashMap,
}
impl配置文件{
fn从磁盘读取磁盘()->Self{
让mut map=HashMap::new();
插入(“name.into(),“Anna.into());
插入(“points.into(),“210.into());
insert(“debug.into(),“true.into());
配置文件{raw:map}
}
fn get(&self,name:&str)->选项
其中T:FromStr
{
self.raw.get(name.)和| u然后(| v | v.parse().ok())
}
}
fn main(){
让conf=ConfigFile::从磁盘()读取磁盘();
让n:String=conf.get(“name”).unwrap();
让p:i32=conf.get(“points”).unwrap();
设d:bool=conf.get(“调试”).unwrap();
println!(“{}有{}个点,{}”,n,p,d);
}

这里有一个可能的解决方案:

枚举值{
布尔(布尔),
Int(i32),
浮动(f32),
Str(字符串),
}
fn获取_值(键:&str)->值{
//从文件中读取值
匹配键{
“b”=>Value::Bool(真),
“i”=>Value::Int(666),
“f”=>Value::Float(42.),
“s”=>Value::Str(“真的很有帮助。我对它进行了一些修改,还制作了一个宏,以避免在
impl Convert
s中出现代码重复。以下是结果,以防有人感兴趣:

trait转换:大小{
fn转换(值)->选项;
}
宏规则!impl\u转换{
($t:ty,$id:ident)=>(
impl转换为$t{
fn转换(v:值)->选项{
比赛五{
值::$id(x)=>Some(x),
_=>没有,
}
}
}
)
}
impl_convert!(bool,bool);
impl_convert!(i32,Int);
impl_convert!(f32,浮点);
impl_convert!(字符串,Str);
fn查询(t:&str)->t{
//…验证等。
匹配T::转换(获取值(T)){
一些(x)=>x,
None=>panic!(“{}`的类型不正确”,t),
}
}
转换
继承
大小
以防止:

警告:未为类型
Self实现trait
core::marker::Sized


啊,这当然有道理。这基本上创建了一个与str
FromStr
并行的特征,但它是根据所讨论的源类型定制的。非常好!尽管为
i32
实现特征并为
i32
创建关联类型似乎是多余的-我认为您不需要关联类型。
use std::collections::HashMap;
use std::str::FromStr;

struct ConfigFile {
    raw: HashMap<String, String>,
}

impl ConfigFile {
    fn read_from_disk() -> Self {
        let mut map = HashMap::new();
        map.insert("name".into(), "Anna".into());
        map.insert("points".into(), "210".into());
        map.insert("debugging".into(), "true".into());
        ConfigFile { raw: map }
    }

    fn get<T>(&self, name: &str) -> Option<T>
        where T: FromStr
    {
        self.raw.get(name).and_then(|v| v.parse().ok())
    }
}

fn main() {
    let conf = ConfigFile::read_from_disk();
    let n: String = conf.get("name").unwrap();
    let p: i32    = conf.get("points").unwrap();
    let d: bool   = conf.get("debugging").unwrap();
    println!("{} has {} points, {}", n, p, d);
}
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("Andrea P's answer was really helpful. I adapted it a little and also made a macro to avoid code duplication in the 
impl Convert
s. Here's the result just in case anyone is interested:

trait Convert : Sized {
    fn convert(Value) -> Option<Self>;
}

macro_rules! impl_convert {
    ($t:ty, $id:ident) => (
        impl Convert for $t {
            fn convert(v: Value) -> Option<$t> {
                match v {
                    Value::$id(x) => Some(x),
                    _ => None,
                }
            }
        }
    )
}

impl_convert!(bool, Bool);
impl_convert!(i32, Int);
impl_convert!(f32, Float);
impl_convert!(String, Str);

fn query<T: Convert>(t: &str) -> T {
    // … validation etc.
    match T::convert(get_value(t)) {
        Some(x) => x,
        None => panic!("`{}` has an incorrect type", t),
    }
}