【问题标题】:How to get the number of elements (variants) in an enum as a constant value?如何将枚举中的元素(变体)数量作为常数值?
【发布时间】:2017-05-29 00:34:56
【问题描述】:

有没有办法提取枚举中的元素个数?

简单示例(带有虚构的number_of_elements 方法):

enum FooBar { A = 0, B, C, };

println!("Number of items: {}", FooBar.number_of_elements());
// "Number of items: 3"

在 C 中我通常会这样做......

enum FooBar { A = 0, B, C, };
#define FOOBAR_NUMBER_OF_ITEMS (C + 1)

但是与此等效的 Rust 不起作用:

enum FooBar { A = 0, B, C, };
const FOOBAR_NUMBER_OF_ITEMS: usize = (C as usize) + 1;

// Raises an error:
//     unimplemented constant expression: enum variants

在枚举中包含最后一项非常不方便,因为如果不考虑所有成员,匹配枚举会出错。

enum FooBar { A = 0, B, C, FOOBAR_NUMBER_OF_ITEMS, };

有没有办法将枚举中的项目数作为常数值?


注意:尽管这与问题没有直接关系,但我想要此功能的原因是我正在使用 builder-pattern 构建一系列仅运行一次才有意义的操作。出于这个原因,我可以使用枚举大小的固定大小数组。

【问题讨论】:

  • 我同意这是一个有用的功能。只是出于兴趣:为什么需要变体的数量?
  • 添加了我为什么要寻找此功能的说明。
  • 老实说,我发现它在 C 和 C++ 中也很不方便,因为我必须处理我的 switch 中的情况,这会污染我的代码。在 C 和 C++ 中,我使用一个宏来声明枚举(黑魔法......),它还声明了一些替代的东西,包括这个非常有用的大小。我想宏也可以在 Rust 中工作......但我希望有更好的东西......(我猜自定义派生也可能做到这一点......)
  • 同意,至少在 C/C++ 中,您可以使用最后一个元素在枚举之外声明一个常量,但视觉上很接近——因此添加新成员的开发人员不太可能忘记更新它(添加示例)。

标签: enums rust


【解决方案1】:

你可以使用procedural macros:

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

#[proc_macro_derive(EnumVariantCount)]
pub fn derive_enum_variant_count(input: TokenStream) -> TokenStream {
    let syn_item: syn::DeriveInput = syn::parse(input).unwrap();
    let len = match syn_item.data {
        syn::Data::Enum(enum_item) => enum_item.variants.len(),
        _ => panic!("EnumVariantCount only works on Enums"),
    };
    let expanded = quote! {
    const LENGTH: usize = #len;
        };
    expanded.into()
}

留给读者作为练习,以确保此派生宏可以在同一模块中多次使用。

要使用宏,只需将#[derive(EnumVariantCount)] 附加到您的枚举。现在应该有一个名为 LENGTH 的全局常量。

【讨论】:

  • 太棒了!但我认为(现在)处理错误(例如非枚举主体)的正确方法是恐慌。非常喜欢this post学习Macros 1.1。
  • 为什么我们会对非枚举感到恐慌?单个变量枚举和元组结构之间没有区别。
  • 好吧,可能是我想的不够。但至少 预计将 #[derive(EnumVariantCount)] 附加到结构定义会导致编译时错误。
  • 对...命名是不幸的。如果将其添加到结构中,则可能是错误的。
猜你喜欢
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 2016-06-27
  • 1970-01-01
相关资源
最近更新 更多