【问题标题】:Why isn't the compiler warns about casting to enum?为什么编译器没有警告关于强制转换为枚举?
【发布时间】:2017-06-07 22:02:54
【问题描述】:

当我意识到 D 允许用户将兼容的值强制转换为 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;
    }
}

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

import greek : GreekLetters, writeGreekLetter;

void main()
{
    writeGreekLetter(cast(GreekLetters)2);
}

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

core.exception.SwitchError@greek(14): No appropriate switch clause found

所以我的问题是:

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

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

注意:我知道,enum 可以有一个基本类型,可以是字符串,在这种情况下 writeGreekLetter 并不真正需要,但这只是一个虚拟示例展示我的主要关注/问题。

【问题讨论】:

  • 可能是因为强制转换是显式的。 Enum 可以保护您避免犯愚蠢的错误,但如果您真的想要的话,仍然可以让您绕过它。可能有一个合法的用例。
  • @Carcigenicate 你能想到什么吗?
  • 我实际上并不知道 D,但在某些情况下,您可能想计算某个 int 值,然后将其转换为对应的 Enum 值。然后,枚举值将取决于计算中的任何内容。
  • @Carcigenicate 在这种情况下,在int 值上使用一个开关(或者如果,无论如何),并根据该值选择正确的enum。我想说的是:还有更安全的选择!

标签: types enums casting d


【解决方案1】:

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

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

writeGreekLetter(2.to!GreekLetters);

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

Value (2) does not match any member value of enum 'GreekLetters'

要在编译时检查整数文字的转换,您可以先使用 CTFE 将其分配给 manifest constant

enum greekLetter2 = 2.to!GreekLetters;
writeGreekLetter(greekLetter2);

此代码将无法正确编译:

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

【讨论】:

  • CTFE 只能使用,如果在编译时该值是已知的,否则程序将无法编译。但这不是最大的问题:我不明白(因此我的第二个问题)是为什么它首先被允许。很容易说,即使cast 是一个低级运算符,也禁止使用它强制转换为enum 类型。其背后的原因是,我想不出任何用例,除了强制转换之外不可能用其他方式解决。
  • 此外,这并不是我第一个问题的真正答案:作为库实施者,那么最佳实践应该是什么?我不能依赖其他开发人员,他们会适当地使用标准库提供的所有东西,所以我不得不假设,他们将使用cast 主要是因为他们可以。我理解,用户承认他/她避免使用类型系统,但这不应该影响我,对吧?
  • 你需要明白一点:D 是一种系统编程语言!如果用户真的想要,他们可以做任何事情,从使用指针算法访问您的私有字段,到用他们自己的覆盖您的函数的机器代码。作为库作者,您无权将任何东西强加给用户 - 只需使用该语言的工具引导他们实现最佳实践。转换是程序员在决定需要时覆盖这些最佳实践的一种方式。
  • 作为库作者的推荐最佳实践: 1. 设计您的库,使其在正确使用的情况下正常工作。 2. 如果检测到代码被错误地使用(表明程序中存在错误),让程序崩溃并出现丑陋的错误。断言、不变量和契约是很好的工具。 3. 如果值来自用户输入(文件或网络),请始终使用enforce 和异常来验证它。
  • 因此,要回答上述问题中的两个问题: 1. 否 - 除非 enum 的值来自文件或网络,否则 final switch 是合适的,并且您的代码很好。 2. 因为转换为enums 在实践中通常很有用,例如如果整数值从文件中读取为int
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多