In Rust can you associate a constant value to each enum variant and then collect those values at compile time?

huangapple go评论72阅读模式
英文:

In Rust can you associate a constant value to each enum variant and then collect those values at compile time?

问题

Here's the translated code snippet:

让我们假设我有一个枚举,并且我想以某种方式注释或关联每个变体与`&str`。例如:
```rust
enum MyEnum {
    A, // "foo"
    B(String), // "bar"
    C(i32) // "baz"
}

我还想将这些&str收集到一个数组中,如下所示:

const arr: [&'static str; 3] = ["foo", "bar", "baz"];

有没有一种在编译时自动执行此操作的好方法?而不是必须单独编写常量数组?也许可以使用宏?

const fn 可以回答第一个问题,但我认为它需要#![feature(const_if_match)],如果可能的话,我更愿意使用稳定的 Rust。我也不确定它是否回答了第二个问题。我还考虑了属性宏,但我不知道是否可以在编译时将这些属性收集在一起。


<details>
<summary>英文:</summary>

Let&#39;s say I have an enum, and I want to somehow annotate or associate each variant with a `&amp;str`. E.g.:

enum MyEnum {
A, // "foo"
B(String), // "bar"
C(i32) // "baz"
}

I would also like to collect these `&amp;str`&#39;s into an array like

const arr:[&'static str; 3] = ["foo", "bar", "baz"];

Is there a nice way to do this automatically at compile time? Rather than having to write out the constant array separately? Perhaps with macros?

A `const fn` would answer the first part, but I believe it requires `#![feature(const_if_match)]`, and I would prefer using stable Rust if possible. I&#39;m also not sure it answered the second part. I also considered attribute macros, but I don&#39;t know how (or whether) you can collect these attributes together at compile time.

</details>


# 答案1
**得分**: 0

您可以使用声明性宏来实现这一点:

```rust
macro_rules! str_variants {
    { enum $enum_name:ident {
        $(
        #[str = $variant_str:literal]
        $variant_name:ident $variant_fields:tt
        ),* $(,)*
    } } => {
        enum $enum_name {
            $(
                $variant_name $variant_fields,
            )*
        }

        impl $enum_name {
            const ARR: &[&'static str] = &[
                $(
                    $variant_str,
                )*
            ];
        }
    }
}

str_variants! { enum MyEnum {
    #[str = "foo"]
    A(),
    #[str = "bar"]
    B(String),
    #[str = "baz"]
    C(i32)
} }

fn main() {
    dbg!(MyEnum::ARR);

    // [src/main.rs:34] MyEnum::ARR = [
    //     "foo",
    //     "bar",
    //     "baz",
    // ]
}

您只需要在单位变体(unit variants)中使用额外的一对括号。

英文:

You can achieve this with a declarative macro:

macro_rules! str_variants {
    { enum $enum_name:ident {
        $(
        #[str = $variant_str:literal]
        $variant_name:ident $variant_fields:tt
        ),* $(,)*
    } } =&gt; {
        enum $enum_name {
            $(
                $variant_name $variant_fields,
            )*
        }

        impl $enum_name {
            const ARR: &amp;[&amp;&#39;static str] = &amp;[
                $(
                    $variant_str,
                )*
            ];
        }
    }
}

str_variants! { enum MyEnum {
    #[str = &quot;foo&quot;]
    A(),
    #[str = &quot;bar&quot;]
    B(String),
    #[str = &quot;baz&quot;]
    C(i32)
} }

fn main() {
    dbg!(MyEnum::ARR);

// [src/main.rs:34] MyEnum::ARR = [
//     &quot;foo&quot;,
//     &quot;bar&quot;,
//     &quot;baz&quot;,
// ]
}

You just need to use an extra pair of parens with unit variants.

playground

huangapple
  • 本文由 发表于 2023年6月12日 23:19:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76458071.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定