为什么编译器没有警告转换为枚举?

Pet*_*aro 2 enums types casting d

当我意识到D允许用户将兼容值转换为a enum并因此可能产生无效enum值时,我感到非常震惊,我认为这在许多层面都存在问题.

因此,例如,如果我创建一个库,我在其中公开一个enum类型和正在处理它的函数:

module greek;

import std.stdio : writeln;

enum GreekLetters
{
    ALPHA,
    BETA,
}


void writeGreekLetter(GreekLetters letter)
{
    final switch(letter)
    {
        case GreekLetters.ALPHA:
            writeln("\u03B1");
            break;

        case GreekLetters.BETA:
            writeln("\u03B2");
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

...然后用户执行以下操作:

import greek : GreekLetters, writeGreekLetter;

void main()
{
    writeGreekLetter(cast(GreekLetters)2);
}
Run Code Online (Sandbox Code Playgroud)

...编译器不会抱怨,但显然程序会崩溃(不太好)异常:

core.exception.SwitchError@greek(14): No appropriate switch clause found
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. 这是否意味着,我,图书馆设计师试图使事情安全(即处理),应该避免使用final switch,并使用其他方法(可能是switch一个default案例的常规)并处理enum那里的无效状态(返回错误,或抛出异常)?

  2. 为什么像D这样的现代安全语言允许我做这样的事情?也就是说,enum首先允许施放的主要原因是什么?(从语言设计的角度来看.)

注意:我知道,enum可以有一个basetype,它可以是字符串,在这种情况下writeGreekLetter并不需要,但这只是一个虚拟的例子来演示我的主要关注/问题.

Vla*_*eev 6

在D中,强制转换是一种钝的低级操作:通过使用它们,程序员承认他们故意避免类型系统限制.(这就是为什么转换语法使用特殊cast关键字 - 通过提供一些greppable来帮助代码审查).

要"安全地"将整数转换为整数枚举,您可以使用std.conv.to.例如:

writeGreekLetter(2.to!GreekLetters);
Run Code Online (Sandbox Code Playgroud)

此代码仍将编译,但会在运行时提供更好的错误消息:

Value (2) does not match any member value of enum 'GreekLetters'
Run Code Online (Sandbox Code Playgroud)

要在编译时检查整数文字的转换,可以先使用CTFE将其分配给清单常量:

enum greekLetter2 = 2.to!GreekLetters;
writeGreekLetter(greekLetter2);
Run Code Online (Sandbox Code Playgroud)

这段代码将无法正确编译:

Error: uncaught CTFE exception std.conv.ConvException("Value (2) does not match any member value of enum 'GreekLetters'"c)
Run Code Online (Sandbox Code Playgroud)