例如,您是否更喜欢这种单线
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解决方案?
什么时候?:
合适,什么时候不合适?应该向初学者讲授还是隐藏起来?
例如,您是否更喜欢这种单线
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解决方案?
什么时候?:
合适,什么时候不合适?应该向初学者讲授还是隐藏起来?
Answers:
三元运算符是邪恶的吗?
不,这是福气。
什么时候?:合适?
当事情变得如此简单时,您不想浪费很多行。
什么时候不呢?
就像您的示例一样,当代码的可读性和清晰度受到影响并且由于注意力不足而导致错误的可能性增加时,例如,许多链接的运算符也是如此。
石蕊测试是当您开始怀疑您的代码从长远来看是否易于阅读和可维护时。那不要做
myVar = someExpression ? false : true;
(someExpression ? var1 : var2)++
:-)
我认为未嵌套的三元运算符(例如,仅使用一次的语句)可以,但是如果嵌套多个,则很难理解。
(我认为)没有人指出的一个区别是if-else不能返回值,而三元运算符可以。
来自F#,我有时喜欢使用三元运算符来模拟模式匹配。
match val with
| A -> 1
| B -> 3
| _ -> 0
与
return val == A ? 1 :
val == B ? 3 :
0;
var res = function() {switch(input) {case 1: return "1"; case 2: return "2"; ...}}()
将开关模拟为表达式。
expression
,statement
但我一直担心我会以错误的方式弄错它们,然后自欺欺人:)
const
以后不能更改的变量也很有用。
绝对不是邪恶的。实际上,它是纯函数,而if-then-else不是。
在Haskell,F#,ML等功能语言中,if-then-else语句被认为是邪恶的。
这样做的原因是,诸如命令式if-then-else语句之类的任何“动作”都要求您将变量声明与其定义分开,并将状态引入到函数中。
例如,在以下代码中:
const var x = n % 3 == 1
? Parity.Even
: Parity.Odd;
与
Parity x;
if (n % 3 == 1)
x = Parity.Even;
else
x = Parity.Odd;
第一个优点是较短,但有两个优点:
x
是一个常量,因此引入错误的机会要少得多,并且有可能以第二种不可能的方式进行优化。x
需要的类型Parity
。令人困惑的是,在功能语言中,三元运算符通常称为if-then-else。在Haskell中,您可能会说x = if n mod 3 == 1 then Odd else Even
。
这种特殊的表情使我的眼睛受伤;我会抨击团队中使用它的任何开发人员,因为它无法维护。
三元运算符使用得当并不是邪恶的。他们甚至不必是一行。格式正确的长篇文章非常清晰易懂:
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;
条件和分配是否允许轻松对齐。我仍然更喜欢三元版本,因为它更短,并且在条件和赋值周围没有太多噪音。
可以将其重新格式化为与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;
}
但是问题是我不确定我是否正确地表示了将要发生的缩进。:-)
if-else
结构好得多。关键是格式。
三元运算符绝非邪恶,而是天赐之物。
当您想在嵌套表达式中做出决定时,它非常有用。经典示例是一个函数调用:
printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
在您的特定示例中,三进制几乎是免费的,因为它是。下的顶级表达式return
。您可以将条件提升到语句级别,而无需复制return
关键字以外的任何内容。
注意:没有任何东西会使中位数的特定算法易于阅读。
printf("I see %d evil construct%s in this program\n", n, "s" unless (n == 1) "s");
这是邪恶的时候的一个例子:
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;
没有什么比三元组更嘈杂了。我想知道三元捷径是否;是否所有表达式都得到求值?
if (x != 0) x = 0;
……
邪恶?看,它们只是不同。
if
是一个声明。(test ? a : b)
是一个表达。他们不是一回事。
存在表示值的表达式。存在执行操作的语句。表达式可以出现在语句内部,反之亦然。因此,您可以在其他表达式中使用三元表达式,例如用于求和项中的项或用于方法的参数等。你不有,但你可以,如果你想。没有错。有人可能会说这很邪恶,但这是他们的意见。
三元表达式的一个值是它使您能够处理正确和错误的情况。if
声明没有。
如果您担心可读性,可以将它们格式化为可读格式。
不知何故,“邪恶的”爬上了编程词汇表。我很想知道谁先丢了它。(实际上,我有一个嫌疑人-他在麻省理工学院。)我宁愿我们有客观的理由来进行这一领域的价值判断,而不仅仅是人们的品味和呼唤。
最大的胜利:表明只有一个行动目标。
if ( $is_whatever )
$foo = 'A';
else
$foo = 'B';
您可以遵循两条代码路径,并且读者必须仔细阅读以了解设置了哪些两个变量。在这种情况下,它只是一个变量,但是读者有更多的阅读要弄清楚。毕竟,可能是这样的:
if ( $is_whatever )
$foo = 'A';
else
$bar = 'B';
使用三元运算符,很明显只设置了一个变量。
$foo = $is_whatever ? 'A' : 'B';
从最低方面讲,这是最基本的DRY(请勿重复自己)原则。如果只能指定$foo
一次,请这样做。
IMO,运算符本身并不邪恶,但是在C(和C ++)中用于该运算符的语法过于简洁。IMO,Algol 60做得更好,所以像这样:
A = x == y ? B : C;
看起来会更像这样(但通常会遵循类似C的语法):
A = if (x==y) B else C;
即使这样,过深的嵌套也可能导致可读性问题,但是至少A)完全完成编程的任何人都可以算出一个简单的嵌套,以及B)理解它的人可以轻松地处理更深层次的嵌套。OTOH,我还要注意,例如在LISP中,a cond
非常类似于三元语句-不是一组语句,而是单个表达式会产生一个值(然后,大多数LISP都是这样。 )
A = (x==y) ? B : C
什么时候是?:合适,什么时候不合适?
应该向初学者讲授还是隐藏起来?
没关系,但是不应故意隐藏它,因为对于初学者来说学习起来并不复杂。
在您的示例中:
def median(a, b, c):
if a < b < c: return b
if a < c < b: return c
if b < a < c: return a
if b < c < a: return c
if c < a < b: return a
if c < b < a: return b
读起来很简单,很明显。<<之间的变量是返回值。
相同,但是更少的代码行。我认为仍然很简单。
def median(a, b, c):
if b<a<c or c<a<b: return a
if a<b<c or c<b<a: return b
if a<c<b or b<c<a: return c
对于const也有必要
const int nLegs = isChicken ? 2: 4 ;
const
某些语言是这样。在C#中const
应该始终是编译时的已知值。这意味着const int nLegs = isChicken ? 2: 4 ;
不会工作,但是const int nLegs = true ? 2: 4 ;
会