在D语言中选择枚举类型的随机元素

8

我已经开始随机从枚举中选择值,像这样:

import std.random : uniform;
import std.stdio : writefln;
import std.conv;

enum E {A, B, C}

int main(){
    auto select = cast(E)uniform(to!int(E.min), to!int(E.max));
    writefln("select %s", select);
    return 0;
}

这段代码非常冗长,如果枚举成员的值超出默认值(或大于int),则容易出现问题。

理想情况下,我希望取一个表示枚举元素的范围,并将其提供给randomSample函数。然而,这似乎是不可能的。

在D语言中是否有更符合惯用法的方法来从枚举中选择随机值?

编辑:

使用fwend提供的答案,这里是一个模板函数,实现了我想要的功能:

T RandomEnumElement(T)() if (is(T == enum)){
    auto members = [EnumMembers!T];
    return members[(uniform(0, members.length))];
}
1个回答

9
import std.random : uniform;
import std.stdio : writefln;
import std.conv;
import std.traits;

enum E {A, B, C}

int main(){
    auto select = [EnumMembers!E][uniform(0, 3)];
    writefln("select %s", select);
    return 0;
}

编辑:如果需要多次使用枚举值,可以先将它们存储在静态不可变数组中,否则每次都要重新构建数组。这样还可以摆脱魔数3。

(...)
int main(){
    static immutable Evalues = [EnumMembers!E];
    auto select1 = Evalues[uniform(0, Evalues.length)];
    writefln("select %s", select1);

    auto select2 = Evalues[uniform(0, Evalues.length)];
    writefln("select %s", select2);
    return 0;
}

编辑2: 如Idan Arye所指出的那样,模板甚至可以更加简洁:

T RandomEnumElement(T)() if (is(T == enum)){
    return [EnumMembers!T][(uniform(0, $))];
}

编辑 3: tgehr 建议以下解决方案,可以在编译时仅构建一次查找表,并完全避免GC分配:

T RandomEnumElement(T)() if (is(T == enum)) {
    static immutable members = [EnumMembers!T];
    return members[uniform(0, $)];
}

目前编辑器无法编译,Evalues 需要类型为 E[] - cmh
@cmh 奇怪,这在我的电脑上可以正常编译通过。dmd 2.060 win7 - fwend
抱歉,它确实可以工作,但在模板函数内部需要参数。 - cmh
你可以使用美元符号($),它代表了数组的长度,而不是使用Evalues.length(或更糟糕的3)。详见http://dlang.org/arrays.html#array-length。 - Idan Arye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接