it-swarm.cn

三元运算符被认为有害吗?

例如,您是否更喜欢这种单线

int median(int a, int b, int c) {
    return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c : b;
}

还是涉及多个return语句的if/else解决方案?

什么时候 ?:合适,什么时候不合适?应该向初学者讲授还是隐藏起来?

82
fredoverflow

三元运算符是邪恶的吗?

不,这是福气。

什么时候?:合适?

当事情变得如此简单时,您不想浪费很多行。

什么时候不呢?

就像您的示例一样,当代码的可读性和清晰度受到影响并且由于注意力不足而导致错误的可能性增加时,例如,使用许多链接运算符。


试金石是当您开始怀疑代码从长远来看是否易于阅读和可维护时。那不要做.

236
user8685

我认为未嵌套的三元运算符(即仅使用一次的语句)是可以的,但是如果嵌套多个,则很难理解。

50
mipadi

什么时候是?

  • 当它使您的代码更简洁易读时。

什么时候不呢?

  • 当它使您的代码不可读时。
  • 如果这样做是为了取悦ReSharper之类的重构工具,而不是需要维护代码的人

如果您在三元表达式中有任何逻辑或函数调用,那么看起来就很恐怖。

24
realworldcoder

(我认为)没有人指出的一个区别是if-else不能返回值,而三元运算符可以。

来自F#,有时我喜欢使用三元运算符来模拟模式匹配。

match val with
| A -> 1
| B -> 3
| _ -> 0

return val == A ? 1 : 
       val == B ? 3 : 
       0;
23
Benjol

有效使用的示例(IMHO):

printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));

与具有2个不同的打印语句相比,这导致代码更具可读性。嵌套的示例取决于:(可理解?是:否)

13
Henno Brandsma

绝对不是邪恶的。实际上,它是 ,而if-then-else不是。

在Haskell,F#,ML等功能语言中,if-then-else语句被认为是邪恶的。

这样做的原因是,诸如命令式if-then-else语句之类的任何“操作”都要求您将变量声明与其定义分开,并在函数中引入 state

例如,在以下代码中:

const var x = n % 3 == 1
    ? Parity.Even
    : Parity.Odd;

vs.

Parity x;
if (n % 3 == 1)
    x = Parity.Even;
else
    x = Parity.Odd;

第一个具有以下优点:

  1. x是一个常数,因此引入错误的机会要少得多,并且有可能以第二种不可能的方式进行优化。
  2. 该类型由表达式明确表示,因此编译器可以毫不费力地推断x必须为Parity类型。

令人困惑的是,在功能语言中,三元运算符通常称为if-then-else。在Haskell中,您可能会说x = if n mod 3 == 1 then Odd else Even

7
Rei Miyasaka

这种特殊的表情使我的眼睛受伤;我会抨击团队中使用它的任何开发人员,因为它无法维护。

三元运算符使用得当并不是邪恶的。他们甚至不必是一行。格式正确的长篇文章非常清晰易懂:

return
      ( 'a' == $s ) ? 1
    : ( 'b' == $s ) ? 2
    : ( 'c' == $s ) ? 3
    :                 4;

我比同等的if/then/else链更好:

if ( 'a' == $s ) {
    $retval = 1;
}
elsif ( 'b' == $s ) {
    $retval = 2;
}
elsif ( 'c' == $s ) {
    $retval = 3;
}
else {
    $retval = 4;
}

return $retval;

我将其重新格式化为:

if    ( 'a' == $s ) { $retval = 1; }
elsif ( 'b' == $s ) { $retval = 2; }
elsif ( 'c' == $s ) { $retval = 3; }
else                { $retval = 4; }

return $retval;

条件和分配是否允许轻松对齐。我仍然更喜欢三元版本,因为它更短并且在条件和赋值周围没有太多噪音。

7
the Tin Man

ReSharper 在VS.NET中有时建议替换if...else?:运算符。

似乎ReSharper仅在条件/块低于特定复杂性级别时建议,否则坚持if...else

3
Uwe Keim

这是当它is邪恶时的示例:

oldValue = newValue >= 0 ? newValue : oldValue;

令人困惑和浪费。编译器可以优化第二个表达式(oldValue = oldValue),但是为什么编码器首先这样做呢?

另一个笨拙:

thingie = otherThingie != null ? otherThingie : null;

有些人并不意味着要成为编码员...

格雷格说等效的if语句是“嘈杂的”。这是如果您吵闹地写的话。但是,如果可以这样写,则为:

if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;

没有什么比三元组更嘈杂了。我想知道三元捷径是否;是否所有表达式都得到求值?

2
hapybrian

三元运算符绝非邪恶,而是天赐之物。

  • 当您要在嵌套表达式中进行决策时,此功能最为有用。经典示例是一个函数调用:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • 在您的特定示例中,三进制几乎是免费的,因为它是return下的顶级表达式。您可以将条件提升到语句级别,而无需复制return关键字以外的任何内容。

N.B.没有什么可以使特定的中值算法易于阅读。

2
Norman Ramsey
  1. 除了“邪恶的”论点外,根据我的经验,我发现程序员使用三元运算符与他或她的整个代码库难以阅读,遵循和维护(如果不是完全没有文档说明)的可能性之间存在高度相关性。如果程序员比能够理解他或她的代码的人更关心节省1-2个字符的行,那么理解三元语句的任何细微混乱通常就是冰山一角。

  2. 三元运算符像s ** t一样吸引魔术数,也吸引苍蝇。

如果我正在寻找一个开放源代码库来解决特定问题,并且在该库的候选对象中看到诸如原始海报的三元运算符之类的代码,警告之钟就会开始响起,我将开始考虑继续前进借给其他项目。

2
user8865

邪恶?看,它们只是不同。

if是一条语句。 (test ? a : b)是一个表达式。他们不是一回事。

存在表示值的表达式。存在执行操作的语句。表达式可以出现在语句内部,反之亦然。因此,您可以在其他表达式中使用三元表达式,例如用于求和项中的项或用于方法的参数等。您不需要必须,但是您如果需要,可以。没有错。有人可能会说这很邪恶,但这是他们的意见。

三元表达式的一个值是它使您能够处理正确和错误的情况。 if语句没有。

如果您担心可读性,可以将它们格式化为可读格式。

不知何故,“邪恶的”爬上了编程词汇表。我很想知道谁先丢了它。 (实际上,我有一个嫌疑人-他在麻省理工学院。)我宁愿我们有客观的理由来进行这一领域的价值判断,而不仅仅是人们的品味和呼唤。

2
Mike Dunlavey

可以将其重新格式化为与if/else组合一样美观:

int median(int a, int b, int c)
{
    return
        (a<b)
        ?
            (b<c)
            ? b
            :
                (a<c)
                ? c
                : a
        :
            (a<c)
            ? a
            :
                (b<c)
                ? c
                : b;
}

但是问题是我不确定我是否正确地表示了将要发生的缩进。 :-)

2
Zan Lynx

我可以说吗?我找不到三元运算的特殊应用evil

  1. 它执行的操作非常简单,一旦您陷入低谷,就几乎不可能出现一些错误;
  2. 函数名称中明确说明了它的作用;
  3. 采取> 1行表示明显的东西,将来显然不会改善(除非魔术中位数算法直到现在还没有被发现)。

请仁慈,我的声誉已经很可怜了。

1
cbrandolino

任何使您的代码更丑陋的东西都是邪恶的。

如果使用三元代码使代码更整洁,请确保使用它。有时像php一样最好进行内联替换,例如.

"Hello ".($Male?"Mr":"Ms")." $Name

这节省了几行,而且很清楚,但是您的示例至少需要更好的格式才能清楚,并且三元数对于多行并不是真正的好方法,那么您最好使用if/else。

1
user11134

最大的胜利:表明只有一个行动目标。

if ( $is_whatever )
    $foo = 'A';
else
    $foo = 'B';

您可以遵循两个代码路径,并且读者必须仔细阅读以了解设置了哪个两个变量。在这种情况下,它只是一个变量,但是读者有更多的阅读要弄清楚。毕竟,可能是这样的:

if ( $is_whatever )
    $foo = 'A';
else
    $bar = 'B';

使用三元运算符,很明显只设置了一个变量。

$foo = $is_whatever ? 'A' : 'B';

在最底层,它是最基本的DRY(请勿重复自己))原则。如果可以指定$foo仅执行一次。

1
Andy Lester

它有一个地方。我曾在许多公司中工作,这些公司的开发人员的技能水平从可怕到巫师不等。由于必须维护代码,而且我不会永远存在,所以我尝试编写一些东西,使它看起来像是属于那里的(不用我的姓名缩写看注释,对于您来说,很少见查看我正在研究的代码,看看我在哪里进行了更改),并且技能比我自己低的人可以维护它。

虽然三元运算符看起来很灵活,但我的经验是代码行将几乎无法维护。在我现在的老板那里,我们有已经出货近20年的产品。我不会在任何地方使用该示例。

1
Tangurena

我认为三元运算符不是邪恶的。

不过,这是让我感到困惑的陷阱。我是许多(10多个)的C程序员,在1990年代后期,我进入了基于Web的应用程序编程。作为一名网络程序员,我很快遇到了PHP,它也具有三元运算符。我在一个PHP)程序中发现了一个错误,最后我找到了一行带有嵌套三元运算符的代码,结果发现PHP三元运算符从左到右相关联,但是C三元运算符(我曾经用来)从右到左相关联。

1
leed25d

什么时候合适,什么时候不合适?

我认为,当为一群齐心协力的人进行开发时,没有问题,但是当您必须与处理不同级别的人员打交道时,这种单行代码只会在代码中引入更复杂的层次。因此,我对此事的政策是:代码清晰而不说明,而不是代码简短说明123123次。

应该向初学者讲授还是隐藏起来?

我不应该教给初学者,而宁愿他们在需求出现时弄清楚它,因此仅在必要时使用它,而不是在您每次需要的时候都使用它。

0
guiman

一家通常编写600-1200行方法的商店不应告诉我,三元是“很难理解的”。 通常允许使用五个条件来评估代码分支的任何商店不应告诉我,三元组中具体总结的条件是“难以阅读的”。

0
Axeman

IMO,运算符本身并不邪恶,但是在C(和C++)中用于该运算符的语法过于简洁。 IMO,ALGOL 60做得更好,所以像这样:

A = x == y ? B : C;

看起来会更像这样(但通常会遵循类似C的语法):

A = if (x==y) B else C;

即使这样,过深的嵌套也可能导致可读性问题,但是至少A)完全完成编程的任何人都可以算出一个简单的嵌套,以及B)理解它的人可以轻松地处理更深层次的嵌套。 OTOH,我还要注意,例如,在LISP中,cond很像三元语句-不是一组语句,而是单个表达式会产生一个值(然后,大多数LISP就是这样...)

0
Jerry Coffin

什么时候?:合适,什么时候不合适?

  • 如果您没有获得性能提升,请不要使用它;它会影响代码的可读性。
  • 只需使用一次,请勿嵌套。
  • 很难调试。

应该教给初学者还是对初学者隐藏?

没关系,但是不应故意隐藏它,因为对于初学者来说学习起来并不复杂。

0
Amir Rezaei

如果……则……否则倾向于强调条件,因此不再强调有条件地进行的操作。

三元运算符则相反,它倾向于隐藏条件,因此在执行操作比条件本身更重要时非常有用。

在某些语言中,有一些技术上的小问题,即它们不是很可互换的,因为一个是语句,一个是表达式,例如有条件地在C++中初始化const

0
jk.