与标准的if-else语句相比,?:运算符的优点和缺点是什么?显而易见的是:
有条件的?:运营商
标准If / Else
根据声明,可读性似乎各不相同。在第一次接触到?:运算符后的一段时间内,我花了一些时间来精确地消化它是如何工作的。您是否会建议尽可能使用它,或者坚持if / else,因为我与许多非程序员一起工作?
答案 0 :(得分:119)
我基本上建议只在结果语句非常短时使用它,并且在不牺牲可读性的情况下表示if / else等效语的简洁性显着增加。
很好的例子:
int result = Check() ? 1 : 0;
错误的例子:
int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;
答案 1 :(得分:50)
其他答案几乎涵盖了这一点,但“这是一个表达”并没有真正解释为什么那么有用......
在C ++和C#等语言中,您可以使用它们定义本地只读字段(在方法体内)。对于传统的if / then语句,这是不可能的,因为readonly字段的值必须在该单个语句中分配:
readonly int speed = (shiftKeyDown) ? 10 : 1;
与:
不同readonly int speed;
if (shifKeyDown)
speed = 10; // error - can't assign to a readonly
else
speed = 1; // error
以类似的方式,您可以在其他代码中嵌入第三个表达式。除了使源代码更紧凑(在某些情况下更可读),它还可以使生成的机器代码更紧凑和高效:
MoveCar((shiftKeyDown) ? 10 : 1);
...可能产生的代码少于必须两次调用相同方法的代码:
if (shiftKeyDown)
MoveCar(10);
else
MoveCar(1);
当然,它也是一种更方便,更简洁的形式(减少打字,减少重复,如果你必须在if / else中复制代码块,可以减少错误的机会)。在干净的“常见模式”案例中:
object thing = (reference == null) ? null : reference.Thing;
...读取/解析/理解(一旦习惯了)比快速if / else等效更快,因此它可以帮助您更快地'grok'代码。
当然,仅仅因为它有用并不意味着在每种情况下使用是最好的。我建议只使用它来获取代码的短代码,其含义是明确的(或更清楚)使用?:
- 如果你在更复杂的代码中使用它,或者在它们之间嵌套三元运算符它可以使代码非常难以阅读。
答案 2 :(得分:13)
我通常选择三元运算符,否则我会有很多重复的代码。
if (a > 0)
answer = compute(a, b, c, d, e);
else
answer = compute(-a, b, c, d, e);
使用三元运算符,可以通过以下方式完成。
answer = compute(a > 0 ? a : -a, b, c, d, e);
答案 3 :(得分:12)
我发现在进行Web开发时,如果我想将变量设置为请求中发送的值(如果已定义)或者某个默认值(如果不是),则会特别有用。
答案 4 :(得分:12)
非常酷的用法是:
x = foo ? 1 :
bar ? 2 :
baz ? 3 :
4;
答案 5 :(得分:6)
条件运算符非常适合短期条件,如下所示:
varA = boolB ? valC : valD;
我偶尔会使用它,因为用这种方式写东西需要的时间更少......不幸的是,浏览代码的其他开发人员有时会错过这种分支。另外,代码通常不会那么短,所以我通常会通过放置代码来帮助提高可读性。和:在不同的行上,像这样:
doSomeStuffToSomething(shouldSomethingBeDone()
? getTheThingThatNeedsStuffDone()
: getTheOtherThingThatNeedsStuffDone());
然而,使用if / else块(以及为什么我更喜欢它们)的一大优势是它以后更容易进入并为分支添加一些额外的逻辑,
if (shouldSomethingBeDone()) {
doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
doSomeAdditionalStuff();
} else {
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}
或添加其他条件:
if (shouldSomethingBeDone()) {
doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
doSomeAdditionalStuff();
} else if (shouldThisOtherThingBeDone()){
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}
所以,最后,它是为了你现在的便利性(使用时间更短:?),以及后来对你(和其他人)的便利。这是一个判断调用...但与所有其他代码格式问题一样,唯一真正的规则是保持一致,并且对于那些必须维护(或评分!)代码的人来说,视觉上很有礼貌。
(所有代码用眼睛编译)
答案 6 :(得分:5)
使用三元运算符时要认识到的一点是表达式而不是语句。
在像scheme这样的函数式语言中,区别不存在:
(if(> a b)a b)
有条件的?:运营商 “似乎没有if / else构造那么灵活”
在函数式语言中。
当用命令式语言编程时,我会在我通常使用表达式(赋值,条件语句等)的情况下应用三元运算符。
答案 7 :(得分:5)
有时它可以使乍一看的值更易于阅读:
// With
button.IsEnabled = someControl.HasError ? false : true;
// Without
button.IsEnabled = !someControl.HasError;
答案 8 :(得分:5)
虽然上述答案有效,并且我同意可读性很重要,但还有两点需要考虑:
这使得使用三元组特别简洁:
string GetDrink(DayOfWeek day)
=> day == DayOfWeek.Friday
? "Beer" : "Tea";
如果您的类型T1
和T2
都可以隐式转换为T
,则以下不工作:
T GetT() => true ? new T1() : new T2();
(因为编译器试图确定三元表达式的类型,T1
和T2
之间没有转换。)
另一方面,下面的if/else
版本确实有效:
T GetT()
{
if (true) return new T1();
return new T2();
}
因为T1
已转换为T
,因此T2
答案 9 :(得分:4)
如果我正在设置一个值,并且我知道它将始终是一行代码,我通常使用三元(条件)运算符。如果我的代码和逻辑有可能在将来发生变化,我会使用if / else,因为对其他程序员来说更清楚。
您可能感兴趣的是?? operator。
答案 10 :(得分:4)
条件运算符的优点是它是一个运算符。换句话说,它返回一个值。由于if
是一个语句,因此无法返回值。
答案 11 :(得分:4)
如果/ else逻辑,我建议将三元(?:)运算符的使用限制为简单的单行赋值。类似这种模式的东西:
if(<boolCondition>) {
<variable> = <value>;
}
else {
<variable> = <anotherValue>;
}
可以轻松转换为:
<variable> = <boolCondition> ? <value> : <anotherValue>;
我会避免在需要if / else if / else,嵌套if / else或if / else分支逻辑导致多行评估的情况下使用三元运算符。在这些情况下应用三元运算符可能会导致无法读取,混乱和无法管理的代码。希望这会有所帮助。
答案 12 :(得分:2)
我最常发现自己使用它的场景是默认值,尤其是返回值
return someIndex < maxIndex ? someIndex : maxIndex;
这些是我觉得很好的唯一地方,但对我们来说,我确实很喜欢。
虽然如果你正在寻找一个布尔值,这有时可能看似合适:
bool hey = whatever < whatever_else ? true : false;
因为它易于阅读和理解,但这个想法应该总是被抛到更明显的位置:
bool hey = (whatever < whatever_else);
答案 13 :(得分:2)
三元运算符可以包含在rvalue中,而if-then-else不能包含在rvalue中;另一方面,if-then-else可以执行循环和其他语句,而三元运算符只能执行(可能无效)rvalues。
在相关的说明中,&amp;&amp;和||运算符允许使用if-then-else更难实现的一些执行模式。例如,如果一个函数有多个函数可以调用并希望执行一段代码,如果它们中的任何一个失败,那么可以使用&amp;&amp;运营商。不使用该运算符执行此操作将需要冗余代码,goto或额外的标志变量。
答案 14 :(得分:2)
如果您需要在相同条件下使用多个分支,请使用if:
if (A == 6)
f(1, 2, 3);
else
f(4, 5, 6);
如果您需要具有不同条件的多个分支,那么如果语句计数会滚雪球,您将需要使用三元组:
f( (A == 6)? 1: 4, (B == 6)? 2: 5, (C == 6)? 3: 6 );
此外,您可以在初始化中使用三元运算符。
const int i = (A == 6)? 1 : 4;
用if做这件事非常麻烦:
int i_temp;
if (A == 6)
i_temp = 1;
else
i_temp = 4;
const int i = i_temp;
您不能将初始化放在if / else中,因为它会更改范围。但引用和const变量只能在初始化时绑定。
答案 15 :(得分:2)
使用the有一些性能优势?例如,运营商。 MS Visual C ++,但这是一个真正的编译器特定的东西。在某些情况下,编译器实际上可以优化条件分支。
答案 16 :(得分:1)
使用 C#7 ,您可以使用新的ref locals功能来简化ref兼容变量的条件分配。那么现在,您不仅可以这样做:
int i = 0;
T b = default(T), c = default(T);
// initialization of C#7 'ref-local' variable using a conditional r-value⁽¹⁾
ref T a = ref (i == 0 ? ref b : ref c);
......但也非常精彩:
// assignment of l-value⁽²⁾ conditioned by C#7 'ref-locals'
(i == 0 ? ref b : ref c) = a;
该行代码会将a
的值分配给b
或c
,具体取决于i
的值。