具有基本类型令人惊讶行为的 D 语言枚举

D lang enum with basetype surprising behaviour

我正在涉足 D,并且对具有指定基类型的命名枚举与匿名枚举的行为感到惊讶。给定以下 D 代码:

import std.stdio;

enum strs : string 
{
    Foo = "Hello", 
    Bar = "World",
}

enum : string 
{
    anon1 = "pen", 
    anon2 = "sword",
}

int main(string[] args)
{
    writefln("%s %s", strs.Foo, strs.Bar);
    writefln("%s %s", anon1, anon2);

    return 0;
}

这输出:

Foo Bar
pen sword

换句话说,对于命名枚举,将值作为字符串传递给 writefln 会打印值的名称,而不是值本身。但是对于匿名枚举,做同样的事情确实会打印值本身。

这似乎是一种奇怪的矛盾。那么这是为什么呢?

我正在使用 Visual D 0.3.42。

无名枚举只是一组清单常量,没有自己的类型。含义:

enum : string 
{
    anon1 = "pen", 
    anon2 = "sword",
}

...与...相同

enum string anon1 = "pen";
enum string anon2 = "sword";

但是,您的 strs 枚举是它自己的一种类型,因此 writefln 打印出枚举字段名称(无论多么奇怪)。

嗯,部分问题是关键字 enum 在 D 中被过度使用了。匿名枚举有时被称为清单常量。声明

enum : string 
{
    anon1 = "pen", 
    anon2 = "sword",
}

基本相同
enum string anon1 = "pen";
enum string anon2 = "sword";

enum anon1 = "pen";
enum anon2 = "sword";

因为它们无论如何都会被推断为 string。这些真的不是枚举。只是您在一个块中而不是单独声明它们。它们更像是 C 语言中的 #defining a constant,因为您声明的符号没有地址,并且在使用该符号的任何地方都将简单地替换为分配给它的值。它不是像 enum 通常应该那样的关联值列表。事实上,这些断言会失败:

assert(is(typeof(anon1) == enum));
assert(is(typeof(anon2) == enum));

那是因为它们是显式常量,而不是传统意义上的真正枚举。与

对比
assert(is(typeof(strs.Foo) == enum));
assert(is(typeof(strs.Bar) == enum));

这将通过 - 因为 strs 是一个实际的 enum 而不是清单常量(尽管枚举类似于清单常量,因为它们没有地址,并且当您使用它们时,它们只需替换为它们的值——这可能是清单常量也使用 enum 关键字的部分原因。

所以,从 writefln 的角度来看,anon1anon2 只是字符串,它会像任何字符串一样打印它们,而 FooBar 是枚举,所以它会打印他们的名字。在内部,writefln 正在使用 is(T == enum) 来检查某物是否是 enum,就像那些断言一样,只有那些是实际枚举而不是清单常量的才会导致该表达式为是的,所以他们是印有自己名字的人。