用rust中的各种表示处理枚举的规范方法

用rust中的各种表示处理枚举的规范方法,rust,Rust,在我的Rust程序中,我为每个大陆使用一个枚举。亚洲、欧洲等。然而,此枚举对应于数据库定义中的整数,它可以从外部源构造,并可以在需要时转换为另一个“类型” 比如说 enum ContinentKind { Asia, Europe, Africa, America, Oceania, } impl ContinentKind { fn new(external_input: &str) -> Result<ContinentK

在我的Rust程序中,我为每个大陆使用一个枚举。亚洲、欧洲等。然而,此枚举对应于数据库定义中的整数,它可以从外部源构造,并可以在需要时转换为另一个“类型”

比如说

enum ContinentKind {
    Asia,
    Europe,
    Africa,
    America,
    Oceania,
}

impl ContinentKind {
    fn new(external_input: &str) -> Result<ContinentKind, String> {
        match external_input {
            "ASIA" => Ok(ContinentKind::Asia),
            "EUROPE" => Ok(ContinentKind::Europe),
            "AFRICA" => Ok(ContinentKind::Africa),
            "AMERICA" => Ok(ContinentKind::America),
            "OCEANIA" => Ok(ContinentKind::Oceania),
            _ => Err("Wrong external input".to_string()),
        }
    }

    fn id(&self) -> u32 {
        match *self {
            ContinentKind::Asia => 1,
            ContinentKind::Europe => 2,
            ContinentKind::Africa => 3,
            ContinentKind::America => 4,
            ContinentKind::Oceania => 5,
        }
    }

    fn api_string(&self) -> String {
        match *self {
            ContinentKind::Asia => String::from("I love Asia"),
            ContinentKind::Europe => String::from("I travel to Europe"),
            ContinentKind::Africa => String::from("Hello Africa"),
            ContinentKind::America => String::from("North and South America"),
            ContinentKind::Oceania => String::from("O C E A N I A"),
        }
    }
}
当我打电话时,乍一看代码是有效的,但我想知道是否有更好的方法来实现这一点,这需要更少的代码

let my_type = ContinentKind::America;
println!("{}", my_type.id());
println!("{}", my_type.api_string());

let another_type = ContinentKind::new("AFRICA");

match another_type {
    Ok(v)=> println!("{}", v.id()),
    _ => println!("an error happend"),
}
我的意思是最终创建这样的结构:

struct Continent {
    id: u32,
    kind: ContinentKind,
    externaL_str : String,
    internal_str: String,
}
lazy_static! {
    static ref ASIA: Continent = Continent::new(1, ContinentKind::Asia, "ASIA", "I love Asia");
    static ref EUROPE: Continent = Continent::new(2, ContinentKind::Europe, "EUROPE", "I travel to Europe");
    // ...
}
它有两个构造,从\u id或从\u external\u str,类型嵌套

例如:

#[derive(Debug)]
struct Continent {
    id: u32,
    kind: ContinentKind,
    external_str : String,
    internal_str: String,
}

impl Continent {

    fn from_external_string(external_input: &str) -> Result<Continent, String> {

        match external_input {

            "ASIA" => Ok(Continent{id: 1, kind:ContinentKind::Asia, external_str: String::from("ASIA"), internal_str:String::from("I love Asia")}),
            "EUROPE" => Ok(Continent{id: 2, kind:ContinentKind::Europe, external_str: String::from("EUROPE"), internal_str:String::from("I travel to Europe")}),
            "AFRICA" => Ok(Continent{id: 3, kind:ContinentKind::Africa, external_str: String::from("AFRICA"), internal_str:String::from("Hello Africa")}),
            "AMERICA" => Ok(Continent{id: 4, kind:ContinentKind::America, external_str: String::from("AMERICA"), internal_str:String::from("North and South America")}),
            "OCEANIA" => Ok(Continent{id: 5, kind:ContinentKind::Oceania, external_str: String::from("OCEANIA"), internal_str:String::from("O C E A N I A")}),
            _ => Err("Wrong external input".to_string()),
        }
    }

    fn from_database_id(id: u32) -> Result<Continent, String> {

        match id {

            1 => Ok(Continent{id: 1, kind:ContinentKind::Asia, external_str: String::from("ASIA"), internal_str:String::from("I love Asia")}),
            2 => Ok(Continent{id: 2, kind:ContinentKind::Europe, external_str: String::from("EUROPE"), internal_str:String::from("I travel to Europe")}),
            3 => Ok(Continent{id: 3, kind:ContinentKind::Africa, external_str: String::from("AFRICA"), internal_str:String::from("Hello Africa")}),
            4 => Ok(Continent{id: 4, kind:ContinentKind::America, external_str: String::from("AMERICA"), internal_str:String::from("North and South America")}),
            5 => Ok(Continent{id: 5, kind:ContinentKind::Oceania, external_str: String::from("OCEANIA"), internal_str:String::from("O C E A N I A")}),
            _ => Err("Wrong external input".to_string()),
        }
    }
}
#[派生(调试)]
构造大陆{
id:u32,
善良的,善良的,
外部_str:String,
内部_str:String,
}
欧洲大陆{
fn来自外部字符串(外部输入:&str)->结果{
匹配外部输入{
“ASIA”=>Ok(大陆{id:1,种类:大陆种类::亚洲,外部_str:String::from(“亚洲”)、内部_str:String::from(“我爱亚洲”)),
“欧洲”=>Ok(大陆{id:2,种类:大陆种类::欧洲,外部字符串::来自(“欧洲”),内部字符串::来自(“我到欧洲旅行”),
“非洲”=>Ok(大陆{id:3,种类:大陆种类::非洲,外部字符:字符串::来自(“非洲”),内部字符:字符串::来自(“你好非洲”),
“美洲”=>Ok(大陆{id:4,种类:大陆种类::美洲,外部字符:字符串::来自(“美洲”),内部字符:字符串::来自(“北美和南美”),
“OCEANIA”=>Ok(大陆{id:5,种类:大陆种类::OCEANIA,外部字符串::from(“OCEANIA”),内部字符串::from(“O C E A N I A”),
_=>错误(“错误的外部输入”。到_字符串()),
}
}
fn来自_数据库_id(id:u32)->结果{
匹配id{
1=>Ok(大陆{id:1,种类:大陆种类::亚洲,外部_str:String::from(“亚洲”),内部_str:String::from(“我爱亚洲”)),
2=>Ok(大陆{id:2,种类:大陆种类::欧洲,外部字符串::来自(“欧洲”),内部字符串::来自(“我到欧洲旅行”),
3=>Ok(大陆{id:3,种类:大陆种类::非洲,外部字符:字符串::来自(“非洲”),内部字符:字符串::来自(“你好非洲”),
4=>Ok(大陆{id:4,种类:大陆种类::美洲,外部的字符串::来自(“美洲”),内部的字符串::来自(“北美和南美”),
5=>Ok(大陆{id:5,种类:大陆种类::大洋洲,外部字符串::from(“大洋洲”),内部字符串::from(“Oceania”),
_=>错误(“错误的外部输入”。到_字符串()),
}
}
}

对于数字覆盖,您可以内联指定以下内容:

#[repr(u32)]
enum Continent {
  Asia = 1,
  Europe = 2,
  ...
}
然后,您可以使用类似板条箱的工具,从/
尝试为您从
实现中派生出
。类似地,您可以使用类似板条箱的方法来派生字符串转换


与您描述的结构相比,这些结构的优点是不占用存储信息冗余副本的额外内存,而需要在运行时执行匹配(这会产生一些开销)而不是简单的结构字段查找。

可以稍微清理一下的一种方法是使用
lazy\u static
将值转换为静态全局值。它的核心是这样的:

struct Continent {
    id: u32,
    kind: ContinentKind,
    externaL_str : String,
    internal_str: String,
}
lazy_static! {
    static ref ASIA: Continent = Continent::new(1, ContinentKind::Asia, "ASIA", "I love Asia");
    static ref EUROPE: Continent = Continent::new(2, ContinentKind::Europe, "EUROPE", "I travel to Europe");
    // ...
}
然后,您可以构建
大陆::from_external_string
大陆::from_database_id
,以返回对这些的引用(如果确实需要值而不是引用,则可以复制)

注意:一般来说,我不喜欢使用global来管理这类事情,但如果您真的想使用硬编码枚举,这至少可以将需要保持同步的位降到最低。

考虑使用claret。
impl ContinentKind {
    fn to_continent(&self) -> &'static Continent {
        match self {
            ContinentKind::Asia => &*ASIA,
            ContinentKind::Europe => &*EUROPE,
            // ...
        }
    }
    fn id(&self) -> u32 {
        self.to_continent().id
    }
    // ...
}