例如,您是否希望使用这种单行代码
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解决方案?
?:
什么时候合适,什么时候不合适?应该向初学者讲授还是隐藏?#1 楼
三元运算符是邪恶的吗?
不,这是一种祝福。
什么时候是?:合适吗?
当事情如此简单时,您不想浪费很多行。
,什么时候不行?
当代码的可读性和清晰度受到影响,并且由于注意力不足而导致错误的可能性增加时,例如,与许多链式运算符一样,就像您的示例一样。
测试是当您开始怀疑代码从长远来看是否易于阅读和可维护时。那那就不要做。
评论
当代码的可读性和清晰度受到损害时,为+1。就像您的示例一样,拥有许多链接运算符。该示例比等价的if / else所需的时间更长。
–sange
2010-12-20在16:44
+1好极了!开发人员不会倾向于意识到某些事情是判断力,他们希望一切都是黑白的。它使我发疯。我遇到过很多人认为“ X是邪恶的,永远不要使用它”。我更喜欢“ X很棒,如果您将X用于其擅长的领域”。
–琼斯医生
2010-12-20 at 16:48
如果使用它也是邪恶的:myVar =(someExpression)?真假;啊!
–adamk
2010-12-20 17:55
@adamk:为邪恶而尝试:myVar = someExpression吗?假:真;
–迪恩·哈丁(Dean Harding)
2010-12-20 22:00
怎么样(someExpression?var1:var2)++ :-)
– fredoverflow
2010-12-21 10:42
#2 楼
我认为未嵌套的三元运算符(即仅使用一次的语句)很好,但是如果嵌套多个,则很难理解。评论
这可能被认为过于简化,但这是一个很容易遵循的指南,并且在大多数情况下都可以使用。
–艾伦·皮尔斯(Alan Pearce)
2010-12-21 15:08
实际上,这是我的经验法则:您永远不要嵌套它们,否则用if / else代替它们,这样会更清楚。
–皮奥韦赞
2014年1月28日19:06
如果您要使用它们并嵌套它们,那么出于对人类的热爱,请使用括号和空白使其可读。 If-else可能很难做到。通过编写编译器可以阅读但人类无法阅读的东西,抵制炫耀自己“聪明”的冲动。总有一天,你将成为无法做到的人。
–candied_orange
14年8月29日在3:00
#3 楼
什么时候是?:适当的什么时候使您的代码更简明易懂。
什么时候不?
什么时候使代码不可读。
如果要这样做,只是为了请一个重构工具,例如ReSharper而不是必须维护代码的人。
如果您在三元表达式中有任何逻辑或函数调用,那么看起来就很恐怖了。
评论
这个值得很多赞扬!
–皮奥韦赞
2014年1月28日在19:07
#4 楼
(我认为)没有人指出的一个区别是if-else无法返回值,而三元运算符可以返回值。来自F#,我有时喜欢使用三元运算符来模拟模式匹配。
match val with
| A -> 1
| B -> 3
| _ -> 0
vs
return val == A ? 1 :
val == B ? 3 :
0;
评论
太酷了。没想到。
–宫阪丽
2010-12-21 14:14
+1 @Benjol:我想指出同样的事情(在F#中,一切都是表达式,包括if / elif / else)。我也像您的示例中一样使用三元数,到目前为止还没有被发现:)。我一直在用Javascript做的另一件事,也许是在上面,是:var res = function(){switch(input){情况1:返回“ 1”;情况二:返回“ 2”; ...}}()将开关模拟为表达式。
–斯蒂芬·斯文森(Stephen Swensen)
2010-12-21 15:05
@Stephen,我本打算使用表达和声明一词,但我一直担心我会以错误的方式弄乱它们,然后自欺欺人:)
– Benjol
2010-12-22 6:02
@Benjol:我知道你的意思!
–斯蒂芬·斯文森(Stephen Swensen)
2010-12-22 13:16
在C和C ++中对初始化以后无法更改的const变量也很有用。
– David Thornley
2011年1月25日19:53
#5 楼
有效使用的示例(IMHO):printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));
这比具有2个不同的打印语句的代码更具可读性。
嵌套示例取决于:(可理解?是:否)
评论
请记住,如果执行此操作,对于必须本地化您的应用程序的人来说,这简直是天壤之别。当然,如果那不是问题,请继续。
– Anon。
2010-12-20 20:23
这是我的经验法则:1级嵌套(在某些情况下)。
–奥利弗·韦勒
2010-12-20 22:56
#6 楼
绝对不是邪恶的。实际上,它是纯粹的,而if-then-else并非如此。在Haskell,F#,ML等功能语言中,if-then-else语句被认为是邪恶的。 br />
这样做的原因是,任何诸如命令式if-then-else语句之类的“动作”都需要您将变量声明与其定义分开,并将状态引入函数。
例如,在以下代码中:
const var x = n % 3 == 1
? Parity.Even
: Parity.Odd;
vs.
Parity x;
if (n % 3 == 1)
x = Parity.Even;
else
x = Parity.Odd;
第一个具有除了更短之外,还有两个优点:
x
是一个常数,因此引入错误的机会要少得多,并且有可能以第二种不可能的方式进行优化。通过表达式可以清楚地表明类型,因此编译器可以毫不费力地推断出
x
必须是Parity
类型。令人困惑的是,在函数式语言中,三元运算符通常被称为-然后-其他。在Haskell中,您可能会说
x = if n mod 3 == 1 then Odd else Even
。评论
是的,这也是@Benjol提出的重点。请参阅我对他的回答的评论,以有趣的方式将switch语句模拟为Java表达式。
–斯蒂芬·斯文森(Stephen Swensen)
2010-12-21 15:10
#7 楼
这种表情使我的眼睛受伤;我会抨击我团队中使用它的任何开发人员,因为它无法维护。使用正确的三元运算符并不有害。他们甚至不必是一行。长格式正确的长条非常清晰易懂:
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;
。我仍然更喜欢三元版本,因为它更短,并且在条件和赋值周围没有太多噪音。
评论
为什么我不能在评论中加入换行符?啊!
–克里斯托弗·马汉(Christopher Mahan)
2011-1-25在20:36
#8 楼
VS.NET中的ReSharper有时建议用if...else
运算符替换?:
。ReSharper似乎仅在条件/块低于特定复杂度级别时才建议使用,否则坚持使用
if...else
。 >评论
我喜欢ReSharper的另一个很棒的功能
–匿名类型
2010-12-20 21:39
#9 楼
除了“邪恶”的论点外,根据我的经验,我发现程序员使用三元运算符与他或她的整个代码库难以阅读,遵循和维护(如果不是完全没有文档证明)的可能性之间存在高度相关性)。如果程序员比能够理解他或她的代码的人更关心节省1-2个字符的行,那么理解三元语句的任何细微混乱通常就是冰山一角。
三元运算符会像s ** t一样吸引魔术数字,也会吸引苍蝇。
如果我正在寻找开放源代码库来解决特定问题,并且看到了原始海报的三元代码等代码该库的候选人中的操作员,在我脑海中会响起警钟,我会开始考虑继续进行其他项目的借鉴。
#10 楼
任何使您的代码更丑陋的东西都是邪恶的。如果您使用三元代码来使代码更整洁,请确保使用它。有时像php一样,最好进行内联替换,例如
"Hello ".($Male?"Mr":"Ms")." $Name
这样可以节省几行,而且很清楚,但是您的示例至少需要更好的格式才能清楚,并且三进制对于多行,那么您最好使用if / else。
#11 楼
三元运算符绝非邪恶,而是天赐之物。当您想在嵌套表达式中做出决定时,它最有用。经典示例是函数调用:
printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
在您的特定示例中,三进制几乎是免费的,因为它是
return
下的顶级表达式。您可以将条件提升到语句级别,而无需重复除return
关键字以外的任何内容。N.B.没有什么能让这种特定的中值算法易于阅读。
评论
很难被人们理解,以至于无法使其变得更好。 printf(“我在该程序中看到%d邪恶的构造%s \ n”,n,“ s”,除非(n == 1)“ s”);
–起搏器
2015年2月6日在13:48
#12 楼
这是邪恶的时候的一个例子: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;
三元数没有什么噪音。我想知道三元捷径是否;所有表达式都得到求值?
评论
您的第二个示例让我想起了如果(x!= 0)x = 0; ...
– fredoverflow
2011年1月25日19:55
#13 楼
邪恶?看,它们只是不同。if
是一条语句。 (test ? a : b)
是一个表达式。它们不是一回事。存在表示值的表达式。存在执行操作的语句。表达式可以出现在语句内,反之亦然。因此,您可以在其他表达式中使用三元表达式,例如用于求和项中的项或用于方法的参数等。
您不必这样做,但也可以。
>这没什么不对。
有人可能会说这很邪恶,但这是他们的见解。
三元表达式的一个价值在于它使您能够处理正确和错误的情况。
if
语句不需要。如果您担心可读性,可以将它们格式化为可读格式。
以某种方式“邪恶”潜入编程词汇表中。我很想知道谁先丢了它。 (实际上,我有一个嫌疑人-他在麻省理工学院。)
我希望我们有客观的理由来进行这一领域的价值判断,而不仅仅是人们的品味和呼唤。
评论
我可以暗示犯罪嫌疑人是谁吗?只是为了提高我对该领域的了解。
– mlvljr
2011年1月26日上午10:52
@mlvljr:我可能是错的,所以最好不要。
–迈克·邓拉维(Mike Dunlavey)
2011-1-26在16:52
#14 楼
它有一个地方。我曾在许多公司中工作,这些公司的开发人员的技能水平从可怕到巫师不等。由于必须维护代码,而且我不会永远存在,所以我尝试编写一些东西,使其看起来像是属于那里的(不用我的姓名缩写看注释,对于您来说,很少见查看我工作过的代码,看看我在哪里进行了更改),并且技能比我自己低的人可以维护它。虽然三元运算符看起来很灵活,但我的经验是代码行将几乎无法维护。在我现在的老板那里,我们有已经出货近20年的产品。我不会在任何地方使用该示例。
#15 楼
我认为三元运算符不是邪恶的。这是让我难过的陷阱。我是许多(10多个)的C程序员,在1990年代后期,我进入了基于Web的应用程序编程。作为一名Web程序员,我很快遇到了PHP,PHP也具有三元运算符。我在一个PHP程序中遇到一个错误,最后我使用嵌套的三元运算符跟踪了一行代码。事实证明,PHP三元运算符从左到右关联,但是C三元运算符(我曾经习惯于)从右到左关联。
#16 楼
可以将其重新格式化为与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;
}
但是问题是我不确定我是否正确地使用了缩进代表实际情况。 :-)
评论
+1我认为这比等效的if-else结构要好得多。关键是格式。
–Orbling
2010-12-20 22:13
如果我在代码库中看到此内容,我将认真考虑寻找一份新工作。
–尼克·拉森(Nick Larsen)
2010-12-21 14:50
+1并非针对此实际缩进,但这是此示例的最佳解决方案。
–马克·赫德
2011-1-26的2:32
只有另一种意外的自动格式设置才能消除所有缩进,并有时间进行另一轮重组-效率很高:)
– nawfal
13年4月23日在19:43
#17 楼
我可以说吗?我无法发现这种三元运算的特殊应用是有害的:它执行的操作非常琐碎,一旦陷入低谷,几乎不可能出现一些错误出
函数名称中清楚地说明了它的作用;
采用> 1行表示如此明显的内容,以至于将来不会明显改善(除非魔术中位数算法直到现在还没有被发现) )。
请怜悯,我的声誉已经可怜了。
#18 楼
最大的胜利:表明有一个单一的行动目标。if ( $is_whatever )
$foo = 'A';
else
$foo = 'B';
您可以遵循两种代码路径,读者必须仔细阅读以查看其中的两种变量被设置。在这种情况下,它只是一个变量,但是读者有更多的阅读要弄清楚。毕竟,可能是这样的:
if ( $is_whatever )
$foo = 'A';
else
$bar = 'B';
使用三元运算符,很明显只设置了一个变量。
$foo = $is_whatever ? 'A' : 'B';
在最底层,这是最基本的DRY(不要重复自己)原则。如果只能指定一次
$foo
,请这样做。#19 楼
如果...则...否则倾向于强调条件,因此不强调要有条件地进行操作。三元运算符则相反,它倾向于隐藏条件,因此很有用当操作完成比条件本身更重要时。
在某些语言中,有一些技术上的小问题,即它们不是很容易互换,因为一个是语句,一个是表达式。有条件地在C ++中初始化const
#20 楼
什么时候合适,什么时候不合适?
我认为,为一群齐心协力的人发展时,没有问题,但必须与人打交道可以处理不同级别的代码,这种单行代码只会向代码引入更复杂的级别。因此,我对此事的政策是:清楚代码,不要解释,而不是简短代码,解释123123次。
应该向初学者讲授还是隐藏? br />
我不应该向初学者学习,而更希望他们在需要时弄清楚,因此仅在必要时使用,而不是在每次您需要if时使用。
#21 楼
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就是这样。 ..)评论
为什么不这样做只是为了提高可读性? A =(x == y)? B:C
–杰里米·海勒(Jeremy Heiler)
2011年1月25日在20:22
@杰里米:虽然有些人认为父母很有用,但即使充其量也没有太大帮助。嵌套多于两个,您仍然需要小心地缩进(至少是最小的数量),以使事情整齐。毫无疑问,最终在Algol中也会发生同样的事情,但是我从来没有说过会像在C中经常遇到的那样出现问题。
–杰里·科芬(Jerry Coffin)
2011年1月25日20:28
我只是假设每个人都同意嵌套三元运算符是不好的。我在专门谈论您提供的示例。特别是,在大多数语言中,第一个可以更像第二个。
–杰里米·海勒(Jeremy Heiler)
2011年1月25日在20:31
#22 楼
定期编写600-1200行方法的商店不应告诉我三元是“很难理解的”。任何定期允许五个条件评估代码分支的商店都不应告诉我,三元数的具体总结条件“很难阅读”。#23 楼
什么时候合适?什么时候不合适?如果没有获得性能上的提高,请不要使用它;它会影响代码的可读性。
只使用一次就不要嵌套。
调试起来比较困难。
应该教给初学者还是对初学者隐藏它?
Dosn没关系,但不应有意将其隐藏起来,因为对于初学者而言,学习起来并不复杂。
#24 楼
在您的示例中: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
评论
在最坏的情况下,这需要进行12次比较...
– fredoverflow
2011-1-25在20:58
也许吧,但这是清晰的。
–克里斯托弗·马汉(Christopher Mahan)
2011-1-25 21:29
#25 楼
对于constconst int nLegs = isChicken ? 2: 4 ;
也很有必要
评论
奇怪。我认为它是C ++之类的。我以为const一直都是编译时间常数(如C#)
– nawfal
13年4月23日在19:48
@nawfal-如果在运行时之前不知道isChicken
–马丁·贝克特(Martin Beckett)
13年4月23日在22:47
是的,那是什么。我认为const在某些语言中是如此。在C#中,const应该始终是编译时的已知值。这意味着const int nLegs = isChicken吗? 2:4;不会工作,但const int nLegs = true吗? 2:4;将
– nawfal
13年4月24日在4:04
评论
它的这种特殊用法是:)谁编码的,四个数字的中位数是什么样的?还是五个?
更正确的名称是“条件运算符”。它恰好是使用中最常见的三元运算符。
这是两年多以前在stackoverflow上提出的。我们现在要重新询问这里的一切吗? stackoverflow.com/questions/160218/to-ternary-or-not-to-ternary
我很惊讶为什么这样的问题不断出现。答案始终是“一切可行且可读”。 -最后一个同样重要。