嵌套三元运算符 vs 嵌套 if else,后者在可读性方面更好

nested ternary operator vs nested if else, which is better in readability purpose

我在代码审查中找到了我的团队成员编写的代码。它包含嵌套的三元运算符。我告诉他如果出于可读性的目的存在不止一个嵌套,就使用 if else。我们为此争论不休。

代码如下

ColorEnum color = opacity == Opacity.FIVE? ColorEnum.BLACK : 
                opacity == Opacity.TEN? ColorEnum.WHITE :
                    opacity == Opacity.FIFTY? ColorEnum.RED :
                        opacity == Opacity.TWENTY? ColorEnum.BLUE :
                            opacity == Opacity.FIFTEEN? ColorEnum.PURPLE : null;

并且此代码会随着新配置的出现而改变。

那么这里有什么更好的呢?三元运算符或 if else?

我建议使用 switch 语句。它将比三元和 if-else 更具可读性。

switch(opticity)
{
    case Opticity.FIVE: color = ColorEnum.BLACK;
    break;

    case Opticity.TEN: color = ColorEnum.WHITE;
    break;

    case Opticity.FIFTY: color = ColorEnum.RED;
    break;  

    ....

   default: printf("Error message\n");
}

为此,就可读性而言,switch-case 语句可能是最好的。

只要重新格式化你的代码就很清楚了:

ColorEnum color = 
          opacity == Opacity.FIVE    ? ColorEnum.BLACK
       :  opacity == Opacity.TEN     ? ColorEnum.WHITE 
       :  opacity == Opacity.FIFTY   ? ColorEnum.RED 
       :  opacity == Opacity.TWENTY  ? ColorEnum.BLUE 
       :  opacity == Opacity.FIFTEEN ? ColorEnum.PURPLE 
       :  null;

LISP 采用了cond结构,既有相同的结构又有相同的语义,被认为是良好的实践。另外,Clojure 还支持一种形式,该形式使用应用于不同值(每个子句一个)的单个谓词来测试单个表达式的值,并将其称为 condp——这将是您用例的完美匹配.

三元运算符的惯用语作为 表达式 优于 if-else 级联,因此您只需要一条语句即可将其分配给变量。 if-else 将迫使您将作业拉入每个 then 子句,引入更多样板代码和更多错误正确性的机会。

switch 语句也可以考虑作为替代方案,但它有以下缺陷:

  • if-else一样,不是表达式;

  • 您只能使用单个表达式的不同 常量 值(表达式的类型也受到很大限制)。

  • 由于样板 break 某处缺失,它很容易出现错误。

使用开关。

我有一个我一直遵循的经验法则(虽然不是硬性设定)

1) 只有一个条件求值,用三元运算符

2) 两个条件检查,用if(){} else if(){ } else{}构造

3) 三个或更多 switch 阶梯

“程序要写出来给人看,顺便给机器看。” ― Harold Abelson,计算机程序的结构和解释

正如其他人所提到的,switch 是一个不错的选择。为了减少样板代码(中断、分配),我进一步建议将开关置于专用方法中:

(所有示例均使用 C#)

public ColorEnum OpacityToColor(Opacity opacity)
{
  switch (opacity)
  {
    case Opacity.FIVE:
      return ColorEnum.BLACK;
    case Opacity.TEN:
      return ColorEnum.WHITE;
    case Opacity.FIFTY:
      return ColorEnum.RED;
    case Opacity.TWENTY:
      return ColorEnum.BLUE;
    case Opacity.FIFTEEN:
      return ColorEnum.PURPLE;
    default:
      throw new System.ArgumentOutOfRangeException("opacity");
  }
}

// Elsewhere
ColorEnum color = OpacityToColor(opacity);

如果您的语言有简洁的 dictionary/map 初始化语法(例如 Python、C#),您也可以使用它来获得非常简洁明了的符号:

public static readonly Dictionary<Opacity, ColorEnum> ColorByOpacity = 
  new Dictionary<Opacity, ColorEnum>
{
  {Opacity.FIVE, ColorEnum.BLACK},
  {Opacity.TEN, ColorEnum.WHITE},
  {Opacity.FIFTY, ColorEnum.RED},
  {Opacity.TWENTY, ColorEnum.BLUE},
  {Opacity.FIFTEEN, ColorEnum.PURPLE}
};

// Elsewhere
ColorEnum color = ColorByOpacity[opacity];