0

在 Zig 0.8.0 中,当切换 u8 字符以获取枚举类型时,我在这段代码中遇到了一个奇怪的编译器错误:

.op_type = switch(c1) {
    '+' => .add, '-' => .sub,
    '*' => .mul, '/' => .div,
    '%' => .mod, '^' => .exp,
    '|' => .bor, '~' => .bxor,
    '&' => .band,
    '<' => if (is_long) .lte else .lt,
    '>' => if (is_long) .gte else .gt,
    '=' => if (is_long) .eq  else .nop,
    '!' => if (is_long) .neq else return TokenError.NotAToken,
    else => unreachable
}

错误是:

.\lib.zig:137:36: error: values of type '(enum literal)' must be comptime known
                        '<' => if (is_long) .lte else .lt,
                               ^

通常在 zig 中,“ must be comptime known”消息意味着我在运行时值上留下了类型签名,例如const x = 3;. 但是,switch 表达式中没有签名,编译器无论如何都应该知道类型是什么,因为该字段.op_type采用Op类型枚举。

我能够通过使用 switch 语句而不是用于分配占位符值的表达式来解决该问题。结果很惨:

var op_type: Op = undefined;
switch(c1) {
    '+' => op_type = .add, '-' => op_type = .sub,
    '*' => op_type = .mul, '/' => op_type = .div,
    '%' => op_type = .mod, '^' => op_type = .exp,
    '|' => op_type = .bor, '~' => op_type = .bxor,
    '&' => op_type = .band,
    '<' => if (is_long) {op_type = .lte;} else {op_type = .lt;},
    '>' => if (is_long) {op_type = .gte;} else {op_type = .gt;},
    '=' => if (is_long) {op_type = .eq ;} else {op_type = .nop;},
    '!' => if (is_long) {op_type = .neq;} else return TokenError.NotAToken,
    else => unreachable
}
...
... {
    ...
    .op_type = op_type
}

我发布这个问题的原因是我并不真正理解第一个实现的问题,我想看看是否有比我想出的更好的解决方案。

4

1 回答 1

0

您正在经历的是枚举文字的怪癖。当您编写.sub时,起初这是一个尚未被强制转换为实际枚举类型的枚举文字。通常这个过程是透明的,但在这种情况下,类型系统似乎无法通过你的if表达式“推理”。

这可能会在自托管编译器中得到改进,但与此同时,解决方案是在遇到此问题时简单地明确枚举类型。

这是编译的代码片段的简化版本:https ://zig.godbolt.org/z/zeTnf3a67

于 2021-07-17T22:11:22.760 回答