【问题标题】:How do I return the string of an enum at a specific index?如何返回特定索引处的枚举字符串?
【发布时间】:2018-05-16 13:41:47
【问题描述】:

实现这一目标的最简单方法是什么?

enum E {
    A,
    B,
    C,
}

// Should return "A" for 0, "B" for 1 and "C" for 2
fn convert(i: u32) -> str {
    // ???
}

【问题讨论】:

  • 它永远无法返回str,因为它没有大小。它需要是String 或&str。
  • 不要像这样使用transmute! 这是非常不安全的,并且可能会导致未定义的行为。 Rust 中的枚举不同于 C 中的枚举:它们不得具有编译器未定义的标记值。如果你不完全理解 Rust 中不安全编码的规则,你不应该使用unsafe 代码。
  • @2080 如果t 超出范围,这将会爆炸。您最好使用match 语句并处理每种情况。
  • 或者,您可以首先让一个宏生成您的enum,同时创建一个to_str 方法。

标签: enums rust


【解决方案1】:

您不能返回 str,但可以返回 &str。结合How do I match enum values with an integer?和Get enum as string的想法:

#[macro_use]
extern crate strum_macros;
extern crate strum;

use strum::IntoEnumIterator;

#[derive(EnumIter, AsRefStr)]
enum E {
    A,
    B,
    C,
}

fn main() {
    let e = E::iter().nth(2);
    assert_eq!(e.as_ref().map(|e| e.as_ref()), Some("C"));
}

【讨论】:

    【解决方案2】:

    需要添加#[derive(Debug)] 属性并在枚举上定义一个实现:

    #[derive(Debug)]
    #[derive(Copy, Clone)]
    enum E {
        A,
        B,
        C,
    }
    
    impl E {
        fn from(t: u8) -> E {
            assert(t<=enum_to_int(E::C), "Enum range check failed!");
            let el: E = unsafe { std::mem::transmute(t) };
            return el;
        }
        fn to_string(&self) -> String {
            return format!("{:?}", self);
        }
    
        fn string_from_int(t: u8) -> String {
            return E::from(t).to_string();
        }
    }
    
    
    fn enum_to_int(el: &E) -> u8 {
        *el as u8
    }
    

    然后可以这样使用:

    fn main() {
        let s = E::string_from_int(3 as u8);
        println!("{}", s);
    }
    

    【讨论】:

    • 为什么这被否决了?它有效并回答了我的问题。
    • 无法保证枚举的表示从 0 开始。此外,您没有进行边界检查。这不会导致一个好的错误——它甚至可能不会导致恐慌——它会导致未定义的行为。
    • 此代码在run in the playground 时会导致段错误。 这是不安全的,不应使用。
    • 值得注意的是,segfault 被触发是因为,正如@PeterHall 提到的,如果你越界,不安全的人不会在意,你告诉它什么就做什么。这就是触发 segfault 的原因:3 超出范围,这里假定的范围是 [0,2]。由于这种类型的转换是所有#[repr(Rust)] 枚举的 UB,因此只有“运气”才能在入站时起作用——Rust 不能保证这一点。但是,对于#[repr(C)] 类 C 枚举,这将是有保证的行为,但这将是糟糕、脆弱的代码,以及糟糕、糟糕的实践。 match 是要走的路,或者@Shepmaster 的答案。
    • 将#[repr(u8)] 添加到枚举中,并将3 更改为2,这样transmute 调用就不会越界,这是使此答案正确所需的最低要求。使其安全 是另一个问题,但您可以通过from 函数中的范围检查来做到这一点。
    猜你喜欢
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 1970-01-01
    • 2021-05-18
    相关资源
    最近更新 更多