三元或不三元?
我个人是三元运算符的提倡者:()? :; 我意识到它有它的位置,但是我遇到了许多完全反对使用它的程序员,而且有些使用它的频率太高。
你对它有什么感想? 你使用过什么有趣的代码?
仅用于简单expression式 :
int a = (b > 10) ? c : d;
不要链接或嵌套三元运营商,因为它很难阅读和混淆:
int a = b > 10 ? c < 20 ? 50 : 80 : e == 2 ? 4 : 8;
而且,在使用三元运算符时,请考虑以提高可读性的方式格式化代码:
int a = (b > 10) ? some_value : another_value;
由于不能在每个子expression式上放置断点,因此它会使debugging稍微困难一些。 我很less使用它。
我爱他们,特别是在types安全的语言。
我不明白这是怎么回事:
int count = (condition) ? 1 : 0;
比这更难:
int count; if (condition) { count = 1; } else { count = 0; }
编辑 –
我认为,三元运营商使一切都不那么复杂,比替代scheme更整齐。
三元?:
运算符仅仅是程序性的构造函数。 所以只要你不使用嵌套的?:
expression式,任何操作的函数表示的参数都适用于这里。 但是,嵌套三元操作可能会导致代码彻底混淆(练习读者:尝试编写一个parsing器来处理嵌套的三元条件,您将会体会到它们的复杂性)。
但有很多情况下,保守使用?:
操作符会导致代码实际上比其他操作更容易阅读。 例如:
int compareTo(Object object) { if((isLessThan(object) && reverseOrder) || (isGreaterThan(object) && !reverseOrder)) { return 1; if((isLessThan(object) && !reverseOrder) || (isGreaterThan(object) && reverseOrder)) { return -1; else return 0; }
现在比较一下:
int compareTo(Object object) { if(isLessThan(object)) return reverseOrder ? 1 : -1; else(isGreaterThan(object)) return reverseOrder ? -1 : 1; else return 0; }
由于代码更紧凑,因此语法噪声更less,通过明智地使用三元运算符(这只与reverseOrder属性有关),最终结果并不特别简洁。
链接我很好 – 嵌套,不是很多。
我倾向于在C语言中更多地使用它们,因为它们是一个有价值的if语句,所以它减less了不必要的重复或variables:
x = (y < 100) ? "dog" : (y < 150) ? "cat" : (y < 300) ? "bar" : "baz";
而不是
if (y < 100) { x = "dog"; } else if (y < 150) { x = "cat"; } else if (y < 300) { x = "bar"; } else { x = "baz"; }
在这样的任务中,我发现重构和清晰都不那么重要。
另一方面,当我在ruby工作时,我更可能使用, if...else...end
因为它也是一个expression式。
x = if (y < 100) then "dog" elif (y < 150) then "cat" elif (y < 300) then "bar" else "baz" end
(不过,无可否认,对于这样简单的事情,我可能只是使用三元运算符)。
这是一个风格问题,真的; 我倾向于遵循的潜意识规则是:
- 只评估1expression式 – 所以
foo = (bar > baz) ? true : false
foo = (bar > baz) ? true : false
,但不是foo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
foo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
- 如果我用它来显示逻辑,例如
<%= (foo) ? "Yes" : "No" %>
<%= (foo) ? "Yes" : "No" %>
只有真正把它用于分配; 从来没有stream逻辑(所以从来没有三元stream动逻辑本身就是一个谎言,忽略了最后一点。(foo) ? FooIsTrue(foo) : FooIsALie(foo)
)
我喜欢它,因为简单的赋值操作简洁而优雅。
像许多意见问题一样,答案是不可避免的: 这取决于
像这样的东西:
return x ? "Yes" : "No";
我认为这比我更简洁(而且我可以更快地parsing)
if (x) { return "Yes"; } else { return "No"; }
现在,如果你的条件expression式是复杂的,那么三元操作不是一个好的select。 就像是:
x && y && z >= 10 && s.Length == 0 || !foo
对三元运算符来说不是一个好的select。
顺便说一下,如果你是一个C程序员,GCC实际上有一个扩展 ,允许你排除三元组的if-true部分,如下所示:
/* 'y' is a char * */ const char *x = y ? : "Not set";
假设y
不是NULL
它将把x
设置为y
。 好东西。
在我看来,只有在需要expression式的情况下使用三元运算符才有意义。
在其他情况下,似乎三元运算符会降低清晰度。
通过圈复杂度的衡量, if
语句或三元运算符的使用是等价的。 那么这个答案是否定的 ,复杂性就和以前一样了。
通过诸如可读性,可维护性和DRY(不重复自己)等其他方法,任何一种select都可能比另一种更好。
我经常在我被约束在构造函数中工作的地方(例如,新的.NET 3.5 LINQ to XML结构)中使用它,以在可选参数为null时定义默认值。
被举的例子:
var e = new XElement("Something", param == null ? new XElement("Value", "Default") : new XElement("Value", param.ToString()) );
或(谢天谢地)
var e = new XElement("Something", new XElement("Value", param == null ? "Default" : param.ToString() ) );
不pipe你是否使用三元运算符,确保你的代码是可读的是重要的。 任何构造都可以变得不可读。
我尽可能使用三元运算符,除非它使得代码非常难以阅读,但是这通常只是表示我的代码可能会使用一些重构。
它总是令我困惑,有些人认为三元运算符是一个“隐藏”的特征,或者有点神秘。 这是我开始用C语言编程学到的第一件事情,我不认为它会降低可读性。 这是语言的自然部分。
我同意jmulder:它不应该被用来代替if
,而是它有其expression的地方或者expression式:
echo "Result: " + n + " meter" + (n != 1 ? "s" : ""); return a == null ? "null" : a;
前者只是一个例子,应该使用更好的i18n复数支持!
如果你使用三元运算符进行简单的条件赋值,我认为没关系。 我已经看到它(ab)用来控制程序stream程,甚至没有做任务,我认为这应该避免。 在这些情况下使用if语句。
(黑客的一天)
#define IF(x) x ? #define ELSE :
那么你可以做if-then-else作为expression式:
int b = IF(condition1) res1 ELSE IF(condition2) res2 ELSE IF(conditions3) res3 ELSE res4;
我认为应该在需要时使用三元运算符。 这显然是一个非常主观的select,但我发现一个简单的expression式(特别是作为一个返回expression式)比一个完整的testing更加清晰。 C / C ++中的示例:
return (a>0)?a:0;
相比:
if(a>0) return a; else return 0;
您也有解决scheme之间的三元运算符和创build一个函数的情况。 例如在Python中:
l = [ i if i > 0 else 0 for i in lst ]
替代scheme是:
def cap(value): if value > 0: return value return 0 l = [ cap(i) for i in lst ]
在Python中(例如)需要足够的时间,这样一个成语可以定期看到:
l = [ ((i>0 and [i]) or [0])[0] for i in lst ]
这一行使用Python中逻辑运算符的属性:它们是懒惰的,如果它等于最终状态,则返回最后计算的值。
我喜欢他们。 我不知道为什么,但是当我使用三元expression时,我感觉非常酷。
我曾经见过这样的野兽(实际上这更糟,因为它是isValidDate,并且每天都检查一次,但是我不能为了记住整个事情而烦恼):
isLeapYear = ((yyyy % 400) == 0) ? 1 : ((yyyy % 100) == 0) ? 0 : ((yyyy % 4) == 0) ? 1 : 0;
显然,一系列if语句本来会更好(虽然这个比我曾经看到的macros观版本还要好)。
我不介意这样的小事情,如:
reportedAge = (isFemale && (Age >= 21)) ? 21 + (Age - 21) / 3 : Age;
甚至有点棘手的事情,如:
printf ("Deleted %d file%s\n", n, (n == 1) ? "" : "s");
我喜欢在debugging代码中使用操作符来打印错误值,所以我不必一直查找它们。 通常我这样做的debugging打印,不会保持一旦我完成开发。
int result = do_something(); if( result != 0 ) { debug_printf("Error while doing something, code %x (%s)\n", result, result == 7 ? "ERROR_YES" : result == 8 ? "ERROR_NO" : result == 9 ? "ERROR_FILE_NOT_FOUND" : "Unknown"); }
我几乎从不使用三元运算符,因为每当我使用它时,总会让我想到比以后更多的时候,当我尝试维护它时。
我喜欢避免冗长,但是当它让代码更容易拾取时,我会去详细search。
考虑:
String name = firstName; if (middleName != null) { name += " " + middleName; } name += " " + lastName;
现在,这有点冗长,但是我发现它比以下更具可读性:
String name = firstName + (middleName == null ? "" : " " + middleName) + " " + lastName;
要么:
String name = firstName; name += (middleName == null ? "" : " " + middleName); name += " " + lastName;
它似乎太多的信息压缩太less的空间,没有明确发生了什么事情。 每次我看到三元操作符被使用,我总是发现一个看起来更容易阅读的替代方法…然后再一次,这是一个非常主观的观点,所以如果你和你的同事发现三元非常可读,就去做吧。
那么,它的语法是可怕的。 我发现函数ifs非常有用,并且经常使代码更具可读性。
我会build议制作一个macros,使其更具可读性,但我敢肯定,有人可以拿出一个可怕的边缘案例(因为总是有CPP)。
只有当:
$ var =(simple> test?simple_result_1:simple_result_2);
吻。
正如其他人所指出的那样,他们对简单的条件很好。 我特别喜欢他们的默认值(类似于||和或 JavaScript和Python中的用法),例如
int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;
另一个常见用法是在C ++中初始化一个引用。 由于引用必须在相同的语句中声明和初始化,所以不能使用if语句。
SomeType& ref = pInput ? *pInput : somethingElse;
我把三元运营商很像GOTO。 他们有自己的位置,但是他们通常应该避免让代码更容易理解。
我最近看到了三元运算符的变体(好,有点),使得标准“()”:“变体似乎是一个清晰的典范:
var Result = [CaseIfFalse, CaseIfTrue][(boolean expression)]
或者,举一个更具体的例子:
var Name = ['Jane', 'John'][Gender == 'm'];
请注意,这是Javascript,所以在其他语言中可能无法使用(谢天谢地)。
对于简单的情况,我喜欢使用它。 实际上,读取/编码例如作为函数的参数或类似的东西要容易得多。 此外,为了避免新的路线,我喜欢保持我所有的if / else。
在我的书中,这将是一个很大的“不”。
所以,恢复一个单一的if / else我将使用三元运算符。 对于其他情况,常规的if / else if / else(或switch)
我通常使用这样的东西:
before: if(isheader) drawtext(x,y,WHITE,string); else drawtext(x,y,BLUE,string); after: drawtext(x,y,isheader==true?WHITE:BLUE,string);
我喜欢Groovy三元运算符的特例,称为Elvis运算符:?:
expr ?: default
如果它不为null,则此代码评估为expr,如果是,则为默认值。 从技术上讲,它不是一个真正的三元运算符,但它确实与它有关,并节省了大量的时间/打字。
对于简单的任务,如根据条件分配不同的值,他们是伟大的。 根据条件不同,我不会使用它们。
有这么多的答案, 这取决于 。 我发现,如果在快速扫描代码时三元比较不可见,则不应使用它。
作为一个侧面的问题,我也可能会注意到,它的存在实际上是一个倒退,因为在C中,比较testing是一个陈述。 在Icon中, if
结构(就像图标的大部分)实际上是一个expression式。 所以你可以做这样的事情:
x[if y > 5 then 5 else y] := "Y"
…我发现比ternery比较运算符更可读。 🙂
最近有一个关于将?:
运算符添加到Icon的可能性的讨论,但是有几个人正确地指出, if
工作的if
,完全没有必要。
这意味着如果你可以用C语言(或其他任何有ternery操作符的语言)来做到这一点,那么事实上根本就不需要ternery操作符。
如果你和你的同事们明白他们做了什么,而他们又不是以大批人创build的,我认为他们让代码更加复杂,更容易阅读,因为代码less了。
唯一一次我认为三元运算符使代码更难理解的是当你在一行中有3或4以上的时候。 大多数人不记得他们是正确的优先顺序,当你有一堆他们是阅读代码的噩梦。