关于多语言:三元还是三元?

To ternary or not to ternary?

我个人是三元运算符的倡导者:()?:;我确实意识到它有它的位置,但是我遇到过许多完全反对使用它的程序员,还有一些经常使用它的程序员。

你对它有什么感觉?您看到使用它的有趣代码了吗?


仅用于简单表达式:

1
int a = (b > 10) ? c : d;

不要链接或嵌套三元运算符,因为很难阅读和混淆:

1
int a = b > 10 ? c < 20 ? 50 : 80 : e == 2 ? 4 : 8;

此外,使用三元运算符时,请考虑以提高可读性的方式格式化代码:

1
2
int a = (b > 10) ? some_value                
                 : another_value;


因为不能在每个子表达式上放置断点,所以调试稍微困难一些。我很少用。


我喜欢它们,特别是在类型安全语言中。

我不明白这是怎么回事:

1
int count = (condition) ? 1 : 0;

比这更难:

1
2
3
4
5
6
7
8
9
10
int count;

if (condition)
{
  count = 1;
}
else
{
  count = 0;
}

编辑-

我认为三元运算符使所有内容都比另一种更复杂、更整洁。


我对嵌套没意见,没什么。

我更倾向于在C语言中使用它们,简单地说,它们是一个有价值的if语句,因此它减少了不必要的重复或变量:

1
2
3
x = (y < 100) ?"dog" :
    (y < 150) ?"cat" :
    (y < 300) ?"bar" :"baz";

而不是

1
2
3
4
     if (y < 100) { x ="dog"; }
else if (y < 150) { x ="cat"; }
else if (y < 300) { x ="bar"; }
else              { x ="baz"; }

在类似这样的任务中,我发现重构更少,更清晰。

另一方面,当我在Ruby中工作时,我更可能使用if...else...end,因为它也是一个表达式。

1
2
3
4
5
x =   if (y < 100) then"dog"
    elif (y < 150) then"cat"
    elif (y < 300) then"bar"
    else               "baz"
    end

(当然,对于这样简单的事情,我可能只使用三元运算符)。


三元?:运算符只是程序if构造的功能等价物。只要您不使用嵌套的?:表达式,任何操作的函数表示的参数/反对的参数在这里都适用。但是嵌套三元操作可能会导致代码完全混淆(读者练习:尝试编写一个解析器来处理嵌套的三元条件,您会欣赏它们的复杂性)。

但在很多情况下,保守使用?:运算符会导致代码实际上比其他方法更容易读取。例如:

1
2
3
4
5
6
7
8
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;              
}

现在把它和这个比较一下:

1
2
3
4
5
6
7
8
int compareTo(Object object) {
    if(isLessThan(object))
        return reverseOrder ? 1 : -1;        
    else(isGreaterThan(object))
        return reverseOrder ? -1 : 1;
    else        
       return 0;              
}

由于代码更紧凑,所以没有太多的句法噪声,并且通过明智地使用三元运算符(仅与ReverseOrder属性相关),最终结果不会特别简洁。


这是一个风格问题,真的;我倾向于遵循的潜意识规则是:

  • 只评估1个表达-so foo = (bar > baz) ? true : false,而不评估foo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
  • 如果我用它来显示逻辑,例如<%= (foo) ?"Yes" :"No" %>
  • only really use it for assignment;never flow logic(so never (foo) ? FooIsTrue(foo) : FooIsALie(foo))flow logic in ternary is itself a lie,ignore that last point.

我喜欢它,因为它对于简单的作业操作来说简洁而优雅。


就像许多意见问题一样,答案是不可避免的:这取决于

比如:

1
return x ?"Yes" :"No";

我认为这比以下内容更简洁(而且对我来说解析速度更快):

1
2
3
4
5
if (x) {
    return"Yes";
} else {
    return"No";
}

如果条件表达式很复杂,那么三元运算就不是一个好的选择。类似:

1
x && y && z >= 10 && s.Length == 0 || !foo

不是三元运算符的好候选者。

顺便提一句,如果您是C程序员,gcc实际上有一个扩展,允许您排除三元的if-true部分,如下所示:

1
2
/* 'y' is a char * */
const char *x = y ? :"Not set";

假设y不是NULL,则将x设为y。好东西。


在我看来,只有在需要表达式的情况下使用三元运算符才有意义。

在其他情况下,似乎三元运算符会降低清晰度。


根据圈复杂度的度量,使用if语句或三元运算符是等效的。因此,通过这种方法,答案是否定的,复杂性将与以前完全相同。

通过其他措施,如可读性、可维护性和干燥性(不要自己重复),任何一种选择都可能比另一种更好。


我经常在约束我在构造函数(例如,新的.NET 3.5 Linq to XML构造)中工作的地方使用它来定义可选参数为空时的默认值。

人为的例子:

1
2
3
4
var e = new XElement("Something",
    param == null ? new XElement("Value","Default")
                  : new XElement("Value", param.ToString())
);

或者(谢谢阿斯泰特)

1
2
3
4
5
6
var e = new XElement("Something",
    new XElement("Value",
        param == null ?"Default"
                      : param.ToString()
    )
);

无论是否使用三元运算符,确保代码可读性都是重要的。任何构造都可能无法读取。


我尽可能使用三元运算符,除非它使代码非常难以读取,但这通常只是表示我的代码可以使用一点重构。

它总是让我困惑,为什么有些人认为三元运算符是一个"隐藏"的特性,或者有点神秘。这是我开始用C语言编程时学到的第一件事,我认为它根本不会降低可读性。它是语言的自然组成部分。


我同意jmulder的观点:不应该用它来代替if,但它有返回表达式或表达式的位置:

1
2
echo"Result:" + n +" meter" + (n != 1 ?"s" :"");
return a == null ?"null" : a;

前者只是一个例子,一个更好的i18n支持复数应该被使用!


(今天的黑客)

1
2
#define IF(x) x ?
#define ELSE :

然后您可以执行if then else as expression:

1
2
3
4
int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;

如果你用三元运算符来做一个简单的条件赋值,我认为没问题。我见过它(ab)用来控制程序流,甚至不做任何分配,我认为应该避免这种情况。在这些情况下使用if语句。


我见过这样的野兽(事实上更糟,因为它是有效的,而且日复一日地检查,但我不想费心去记住整件事):

1
2
3
4
5
6
7
8
isLeapYear =
    ((yyyy % 400) == 0)
    ? 1
    : ((yyyy % 100) == 0)
        ? 0
        : ((yyyy % 4) == 0)
            ? 1
            : 0;

其中,显然,一系列if语句会更好(尽管这一个比我曾经看到的宏版本要好)。

我不介意做一些小事情,比如:

1
reportedAge = (isFemale && (Age >= 21)) ? 21 + (Age - 21) / 3 : Age;

或者是一些稍微有点棘手的事情,比如:

1
2
printf ("Deleted %d file%s
", n, (n == 1) ?"" :"s");


我认为三元运算符应该在需要时使用。这显然是一个非常主观的选择,但我发现一个简单的表达式(特别是作为返回表达式)比完整的测试更清楚。C/C++中的例子:

1
return (a>0)?a:0;

相比:

1
2
if(a>0) return a;
else return 0;

在这种情况下,解决方案位于三元运算符和创建函数之间。例如,在python中:

1
l = [ i if i > 0 else 0 for i in lst ]

另一种选择是:

1
2
3
4
5
def cap(value):
    if value > 0:
        return value
    return 0
l = [ cap(i) for i in lst ]

在python中(作为一个例子),这样的一个习惯用法是非常必要的:

1
l = [ ((i>0 and [i]) or [0])[0] for i in lst ]

这一行使用了python中逻辑运算符的属性:它们是懒惰的,如果最后一个值等于最终状态,则返回计算得出的值。


我喜欢它们。我不知道为什么,但当我使用三元表达式时,我觉得很酷。


我几乎从不使用三元运算符,因为每当我使用它时,它总是使我比以后试图维护它时要思考的更多。

我喜欢避免冗长的代码,但是当它使代码更容易被获取时,我会选择冗长的代码。

考虑:

1
2
3
4
5
6
7
String name = firstName;

if (middleName != null) {
    name +="" + middleName;
}

name +="" + lastName;

现在,这有点冗长,但我发现它比:

1
2
String name = firstName + (middleName == null ?"" :"" + middleName)
    +"" + lastName;

或:

1
2
3
String name = firstName;
name += (middleName == null ?"" :"" + middleName);
name +="" + lastName;

它似乎只是把太多的信息压缩到了太少的空间,而没有弄清楚到底发生了什么。每当我看到三元运算符被使用时,我总是找到一个更容易阅读的替代方法…再说一次,这是一个非常主观的意见,所以如果你和你的同事发现三元非常可读,就去做。


我喜欢在调试代码中使用操作符来打印错误值,这样我就不必一直查找它们。通常我这样做是为了调试那些一旦我完成开发就不会保留的打印。

1
2
3
4
5
6
7
8
9
10
int result = do_something();
if( result != 0 )
{
  debug_printf("Error while doing something, code %x (%s)
", result,
                result == 7 ?"ERROR_YES" :
                result == 8 ?"ERROR_NO" :
                result == 9 ?"ERROR_FILE_NOT_FOUND" :
               "Unknown");
}


正如其他人所指出的,它们适用于短而简单的条件。我特别喜欢它们的默认值(有点像和或在javascript和python中的用法),例如

1
int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

另一个常用的用法是初始化C++中的引用。由于引用必须在同一语句中声明和初始化,因此不能使用if语句。

1
SomeType& ref = pInput ? *pInput : somethingElse;


我通常用在这样的事情上:

1
2
3
4
5
6
7
8
9
10
before:

if(isheader)
    drawtext(x,y,WHITE,string);
else
    drawtext(x,y,BLUE,string);

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);


嗯,它的语法很可怕。我发现函数式ifs非常有用,并且经常使代码更可读。

我建议做一个宏来提高可读性,但我相信有人会想出一个可怕的边缘情况(就像CPP总是那样)。


只有当:

$var=(简单>测试?简单结果1:简单结果2);

吻。


如果你和你的同事理解他们所做的事情,并且他们不是在大量的团队中创建的,我认为他们会使代码不那么复杂,更容易阅读,因为代码的数量非常少。

唯一一次我认为三元运算符使代码更难理解是当一行中有超过3或4个的时候。大多数人都不记得它们是基于正确的优先级,当你有一堆它们的时候,阅读代码就成了一场噩梦。


我喜欢groovy的三元运算符的特殊情况,称为elvis运算符:?:

1
expr ?: default

如果不为空,则此代码计算为expr;如果为空,则默认为expr。从技术上讲,它不是真正的三元运算符,但它确实与之相关,并且节省了大量的时间/输入。


我最近看到了三元运算符(好吧,有点类似)的一种变体,它使标准"()?:"变体似乎是清晰的典范:

1
var Result = [CaseIfFalse, CaseIfTrue][(boolean expression)]

或者,举一个更具体的例子:

1
var Name = ['Jane', 'John'][Gender == 'm'];

请注意,这是JavaScript,所以类似的事情在其他语言中是不可能实现的(谢天谢地)。


对于简单的任务,比如根据条件分配不同的值,它们是很好的。当有更长的表达式时,我不会使用它们,这取决于条件tho。


我对待三元运算符很像goto。它们有它们的位置,但是它们通常是您应该避免的,以使代码更容易理解。


对于简单的if案例,我喜欢使用它。实际上,作为函数或类似函数的参数来读取/编码要容易得多。同时为了避免新的生产线,我喜欢和所有的if/else保持一致。

在我的书中,这将是一个很大的禁忌。

所以,继续,对于单个if/else,我将使用三元运算符。对于其他情况,常规if/else if/else(或开关)


有这么多答案说,这要看情况而定。我发现如果在快速扫描代码时看不到三元比较,那么就不应该使用它。

作为一个附带问题,我可能也注意到它的存在实际上有点反常,因为在C中,比较测试是一种声明。在icon中,if构造(与大多数icon一样)实际上是一个表达式。所以你可以这样做:

1
x[if y > 5 then 5 else y] :="Y"

…我发现它比一个简洁的比较运算符更易读。-)

最近有人讨论过将?:运算符添加到图标的可能性,但有几个人正确地指出,由于if的工作方式,完全没有必要这样做。

这意味着,如果你可以用C语言(或者其他任何一种使用ternery操作符的语言)来实现这一点,那么实际上你根本不需要ternery操作符。


三元运算符下手。如果格式正确,它们就不复杂。以@paxdiablo的闰年为例:

1
2
3
4
5
6
7
8
$isLeapYear =
   (($year % 400) == 0)
   ? 1
   : ((($year % 100) == 0)
      ? 0
      : ((($year % 4) == 0)  
         ? 1
         : 0));

这可以写得更简洁,并且使用这种格式更易于阅读:

1
2
3
4
5
//--------------test expression-----result
$isLeapYear = (($year % 400) == 0) ? 1 :
              ((($year % 100) == 0)? 0 :
              ((($year % 4) == 0)  ? 1 :
                                     0));//default result

我最近制定的确定是否应使用三元运算符的经验法则是:

  • 如果代码在两个不同的值之间进行选择,请继续使用三元运算符。
  • 如果您的代码在两个不同的代码路径之间进行选择,请坚持使用if语句。

善待你的代码的读者。如果要嵌套三元运算符,请格式化代码以使嵌套明显。


我要说的是,逻辑表达式中的条件数量使它更难阅读。这对于if语句是正确的,对于三元运算符也是正确的。在一个完美的世界里,应该有一个可以总结的理由去选择一个分支,而不是其他分支。如果您的解释是"仅当这组状态发生时",那么很可能它实际上更像是一个"业务规则"。

然而,在现实世界中,我们并没有添加中间步骤来将状态折叠成一个可表示状态,而只是为了服从理想情况。我们已经对多个状态做出了推论,并且必须决定如何处理它们。

我喜欢三元,因为它可以用if语句做任何事情。

1
2
3
4
5
6
if( object.testSomeCondition()) {
    System.exec("format c:" );
}
else {
    a++;
}

另一方面:

1
a += ( object.testSomeCondition() ? 0 : 1 );

明确目标是为a找到一个值。当然,按照这一点,可能不应该有超过合理的副作用。

  • 在我决定是否有时间对上游的条件进行返工以便回答一个更简单的问题之后,我将if用于长期或复杂的条件。但是当我使用if时,我仍然尝试在不同的条件下进行并行处理。

    1
    2
    3
    4
    5
    if (  user.hasRepeatedlyPressedOKWithoutAnswer()
       && me.gettingTowardMyLunchtime( time )
       ) {
        ...
    }
  • 我的目标也是接近单流处理。所以我经常尝试不做一个else,而if仅仅是一个偏离共同道路的步骤。当您进行大量的单流处理时,bug很难隐藏在您的代码中,等待一个条件跳出并打破它。

  • 正如我上面所说,如果你用一个三元来设置一个东西,或者你有一个小的案例,你想测试,以设置为一个值,那么我就像一个三元的可读性。

  • 有一个警告——>没有复杂的真子句

    1
    a = b == c ? ( c == d ? ( c == e ? f : g ) : h ) : i;

当然可以分解为:

1
2
3
4
5
a = b != c ? i
  : c != d ? h
  : c == e ? f
  :          g
  ;

它看起来像一个(压缩的)真值表。

记住,可读性还有更重要的因素,一个是块长度,另一个是缩进级别。在三元中做一些简单的事情并不能推动进一步的压痕。


不,很难读懂。如果/否则更容易阅读。

这是我的意见。您的里程可能会有所不同。


使用它:

  • 访问对象(数组)属性:ZZU1〔7〕
  • 返回语句:ZZU1〔8〕
  • 初始化变量:

    1
    var formMethod = DEBUG_FLAG == true ?"GET" :"POST";

    • 验证参数:

    1
    2
    3
    4
    5
    6
    function(object){
    var prop1 =  typeof object.property == 'undefined'
             ?"default prop"
             : object.property;
    //...
    }

代码示例在javascript中


如果没有三元运算符,如何赢得模糊代码竞赛?!

在适当的时候,我会亲自使用它,但我认为我永远不会嵌套它。它是非常有用的,但是它有一些缺点,因为它使代码更难阅读,并且在其他一些操作(如groovy的空检查)中被其他语言使用。


这取决于:

在处理可能的空引用时,它们是有用的(BTW:Java确实需要一种方法来轻松地比较两个可能的空字符串)。

当您在一个表达式中嵌套多个三元运算符时,问题就开始了。


使代码更小并不总是意味着更容易解析。在不同的语言中。例如,在PHP中,鼓励使用空格和换行符,因为PHP的lexer首先将代码以位分隔,从换行符开始,然后是空格。所以我看不到性能问题,除非使用更少的空白。

坏的:

1
($var)?1:0;

好:

1
($var) ? 1 : 0;

这似乎不是一个大问题,但是对于用PHP编写的词法代码,空白是必不可少的。另外,这样读起来也更好一点。


我同意这里许多海报的观点。只要正确使用三元运算符并且不引入歧义(公平地说,您可以对任何运算符/构造这样说),它就完全有效。

我经常在嵌入式代码中使用三元运算符来澄清我的代码在做什么。取以下(为了清晰起见过于简单化)代码示例:

片段1:

1
2
3
4
5
6
int direction = read_or_write(io_command);

// Send an I/O
io_command.size = (direction==WRITE) ? (32 * 1024) : (128 * 1024);
io_command.data = &buffer;
dispatch_request(io_command);

片段2:

1
2
3
4
5
6
7
8
9
10
11
12
int direction = read_or_write(io_command);

// Send an I/O
if (direction == WRITE) {
    io_command.size = (32 * 1024);
    io_command.data = &buffer;
    dispatch_request(io_command);
} else {
    io_command.size = (128 * 1024);
    io_command.data = &buffer;
    dispatch_request(io_command);
}

这里,我正在发送一个输入或输出请求。无论请求是读还是写,过程都是相同的,只有默认的I/O大小会改变。在第一个示例中,我使用三元运算符来明确说明过程是相同的,并且size字段根据I/O方向获得不同的值。在第二个例子中,并不是很清楚这两种情况下的算法是相同的(特别是当代码增长的长度超过三行时)。第二个例子将更难保持公共代码的同步。在这里,三元运算符更好地表达代码的基本并行性。

三元运算符还有另一个优点(尽管通常这只是嵌入式软件的一个问题)。有些编译器只能在代码没有"嵌套"超过某个深度时执行某些优化(即在函数内部,每次输入if、loop或switch语句时将嵌套深度增加1,并在离开时将其减少1)。有时,使用三元运算符可以最小化需要在条件内的代码量(有时到编译器可以优化去掉条件的程度),并可以减少代码的嵌套深度。在某些情况下,我可以使用三元运算符(如我上面的示例中所示)重新构造某些逻辑,并将函数的嵌套深度降低到足够的程度,以便编译器可以对其执行其他优化步骤。诚然,这是一个相当狭窄的用例,但我认为无论如何都值得一提。


我喜欢在某些情况下使用操作符,但我认为有些人倾向于过度使用它,这会使代码更难阅读。

我最近在一些我正在修改的开源代码中偶然发现了这一行。

1
2
3
where
               (active == null ? true :
               ((bool)active ? p.active : !p.active)) &&...

而不是

1
where ( active == null || p.active == active) &&...

我想知道在这种情况下,三元用法是否会给Linq语句增加额外的开销。


似乎没有人提到使用三元运算符的一个原因,至少在支持类型推断的D等语言中,这是为了让类型推断适用于异常复杂的模板类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
auto myVariable = fun();  
// typeof(myVariable) == Foo!(Bar, Baz, Waldo!(Stuff, OtherStuff)).

// Now I want to declare a variable and assign a value depending on some
// conditional to it.
auto myOtherVariable = (someCondition) ? fun() : gun();

// If I didn't use the ternary I'd have to do:
Foo!(Bar, Baz, Waldo!(Stuff, OtherStuff)) myLastVariable;  // Ugly.
if(someCondition) {
    myLastVariable = fun();
} else {
    myLastVariable = gun():
}

在小剂量的情况下,它们可以减少行数并使代码更具可读性;特别是当结果类似于根据计算结果将char字符串设置为"yes"或"no"时。

例子:

1
2
3
4
5
6
char* c = NULL;
if(x) {
  c ="true";
}else {
  c ="false";
}

与:

1
char* c = x ?"Yes" :"No";

在这种简单的测试中,唯一可能出现的错误是分配了一个不正确的值,但是由于条件通常很简单,所以程序员很少会出错。让您的程序打印错误的输出并不是世界末日,应该在所有的代码审查、测试台测试和生产测试阶段都能看到。

我将反驳我自己的论点,现在使用代码覆盖率度量来帮助了解测试用例有多好变得更加困难。在第一个示例中,您可以在两个分配行上测试覆盖率;如果其中一个没有覆盖,那么您的测试就没有运行所有可能的代码流。

在第二个示例中,行将显示为正在执行,而不考虑x的值,因此您不能确定是否已测试了备用路径(ymmv,取决于覆盖工具的能力)。

随着测试复杂性的增加,这一点更为重要。


string somesay=bcanreadthis?""不":"是";


三元运算符对于简洁地生成逗号分隔列表非常有用。下面是一个Java示例:

1
2
3
4
5
6
    int[] iArr = {1,2,3};
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < iArr.length; i++) {
        sb.append(i == 0 ? iArr[i] :"," + iArr[i]);
    }
    System.out.println(sb.toString());

产生:"1,2,3"

否则,最后一个逗号的特殊大小写将变得烦人。


不(除非使用不当)。如果表达式是更大表达式的一部分,则三元运算符的使用通常更清楚。


有趣的轶事:我见过优化器weight三元运算符对于内联的目的来说比等价的if要轻一些。我在微软的编译器中注意到了这一点,但它可能更广泛。

特别是像这样的函数将内联:

1
2
3
4
int getSomething()
{
   return m_t ? m_t->v : 0;
}

但这不会:

1
2
3
4
5
6
int getSomething()
{
    if( m_t )
        return m_t->v;
    return 0;
}

我曾经在"三元运算符使一行字不可读"的阵营中,但在过去的几年里,我越来越喜欢在适度使用时使用它们。如果团队中的每个人都知道发生了什么,那么单线三元运算符可以提高可读性。这是一种简洁的方法,不需要花很多花括号来代替花括号。

我不喜欢这两种情况:如果它们超出了120列标记,或者它们嵌入到其他三元运算符中。如果你不能快速、轻松、易读地表达你在三元运算符中所做的事情。然后使用if/else等效值。


不,三元运算符不会增加复杂性。不幸的是,一些开发人员过于注重命令式编程风格,以至于他们拒绝(或不愿意学习)任何其他东西。我不相信,例如:

1
int c = a < b ? a : b;

比等价物"更复杂"(但更详细):

1
2
3
4
5
6
int c;
if (a < b) {
    c = a;
} else {
    c = b;
}

或者更尴尬的(我见过):

1
2
3
4
int c = a;
if (!a < b) {
    c = b;
}

这就是说,仔细看你的备选方案。假设一个受过良好教育的开发人员,询问哪一个最简洁地表达了代码的意图,然后使用该意图。


如果您试图减少代码中的行数或正在重构代码,那么就开始吧。

如果你关心下一个需要花费0.1毫秒来理解表达式的程序员,那么无论如何都要使用它。


如果你的三元运算符最终占用了整个屏幕宽度,那么我不会使用它。我让它只检查一个简单条件并返回单个值:

1
int x = something == somethingElse ? 0 : -1;

实际上,我们在生产中有一些这样的讨厌代码……不好:

1
int x = something == (someValue == someOtherVal ? string.Empty :"Blah blah") ? (a == b ? 1 : 2 ): (c == d ? 3 : 4);


我使用并推荐三元来避免在逻辑不重要的情况下使用代码行。

1
2
3
4
5
6
int i;
if( piVal ) {
    i = *piVal;
} else {
    i = *piDefVal;
}

在上述情况下,我会选择三元,因为它的噪声较小:

1
int i = ( piVal ) ? *piVal : *piDefVal;

同样,条件返回值也是很好的候选者:

1
return ( piVal ) ? *piVal : *piDefVal;

我认为紧凑性可以提高可读性,这反过来有助于提高代码质量。

但可读性始终取决于代码的受众。

读者必须能够理解a ? b : c模式,而无需任何脑力劳动。如果你不能假定这一点,那就用长版本吧。


我非常喜欢。当我使用它时,我把它写成if-then-else:条件、真操作和假操作各一行。这样,我就可以很容易地把它们筑巢。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
x = (a == b
     ? (sqrt(a)-2)
     : (a*a+b*b)
     );

x = (a == b
     ? (sqrt(a)-2)
     : (a*a+b*b)
     );
x = (a == b
     ? (c > d
        ? (sqrt(a)-2)
        : (c + cos(d))
       )
     : (a*a+b*b)
     );

对我来说,这相当容易阅读。它还可以很容易地添加子案例或更改现有案例。


我认为这真的取决于他们所处的环境。

像这样的东西会是一种非常混乱的,尽管有效的使用方法:

1
2
3
4
5
6
 __CRT_INLINE int __cdecl getchar (void)
{
   return (--stdin->_cnt >= 0)
          ?  (int) (unsigned char) *stdin->_ptr++
          : _filbuf (stdin);
}

然而,这:

1
c = a > b ? a : b;

完全合理。

我个人认为,在减少过于冗长的if语句时应该使用它们。问题是,人们要么被他们吓坏了,要么非常喜欢他们,他们几乎完全被使用而不是if语句。


我很喜欢…在适当的时候。

像这样的东西很好,就我个人而言,我不觉得太难阅读/理解:

1
2
3
4
$y = ($x =="a" ?"apple"
   : ($x =="b" ?"banana"
   : ($x =="c" ?"carrot"
   :"default")));

不过,我知道这可能会让很多人畏缩。

在PHP中使用它时要记住的一点是,它如何处理返回引用的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Foo {
    var $bar;
    function Foo() {
        $this->bar ="original value";
    }
    function &tern() {
        return true ? $this->bar : false;
    }
    function &notTern() {
        if (true) return $this->bar;
        else      return false;
    }
}

$f = new Foo();
$b =& $f->notTern();
$b ="changed";
echo $f->bar;  //"changed"

$f2 = new Foo();
$b2 =& $f->tern();
$b2 ="changed";
echo $f2->bar;  //"original value"