具有基本类型令人惊讶行为的 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
的角度来看,anon1
和 anon2
只是字符串,它会像任何字符串一样打印它们,而 Foo
和Bar
是枚举,所以它会打印他们的名字。在内部,writefln
正在使用 is(T == enum)
来检查某物是否是 enum
,就像那些断言一样,只有那些是实际枚举而不是清单常量的才会导致该表达式为是的,所以他们是印有自己名字的人。
我正在涉足 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
的角度来看,anon1
和 anon2
只是字符串,它会像任何字符串一样打印它们,而 Foo
和Bar
是枚举,所以它会打印他们的名字。在内部,writefln
正在使用 is(T == enum)
来检查某物是否是 enum
,就像那些断言一样,只有那些是实际枚举而不是清单常量的才会导致该表达式为是的,所以他们是印有自己名字的人。