你为什么要在条件下使用作业?

时间:2008-09-30 05:24:44

标签: variable-assignment conditional-statements

在许多语言中,作业在条件上是合法的。我从来不明白这背后的原因。你为什么要写:

if (var1 = var2) {
  ...
}

而不是:

var1 = var2;
if (var1) {
  ...
}

12 个答案:

答案 0 :(得分:98)

它比if语句更有用于循环。

while( var = GetNext() )
{
  ...do something with var 
}

否则必须写出

var = GetNext();
while( var )
{
 ...do something
 var = GetNext();
}

答案 1 :(得分:29)

如果你正在调用一个函数,它会更有用:

if (n = foo())
{
    /* foo returned a non-zero value, do something with the return value */
} else {
    /* foo returned zero, do something else */
}

当然,你可以把n = foo();在一个单独的声明中,如果(n),但我认为以上是一个相当可读的习语。

答案 2 :(得分:29)

我发现它在行动链中最有用,通常涉及错误检测等。

if ((rc = first_check(arg1, arg2)) != 0)
{
    report error based on rc
}
else if ((rc = second_check(arg2, arg3)) != 0)
{
    report error based on new rc
}
else if ((rc = third_check(arg3, arg4)) != 0)
{
    report error based on new rc
}
else
{
    do what you really wanted to do
}

备选方案(不使用条件中的赋值)是:

rc = first_check(arg1, arg2);
if (rc != 0)
{
    report error based on rc
}
else
{
    rc = second_check(arg2, arg3);
    if (rc != 0)
    {
        report error based on new rc
    }
    else
    {
        rc = third_check(arg3, arg4);
        if (rc != 0)
        {
            report error based on new rc
        }
        else
        {
            do what you really wanted to do
        }
    }
}

通过长时间的错误检查,替代方案可以运行页面的RHS,而条件分配版本不会这样做。

错误检查也可以是“操作” - first_action()second_action()third_action() - 当然,而不仅仅是检查。也就是说,可以在函数管理的过程中检查它们。 (通常在我使用的代码中,函数是前置条件检查,或函数工作所需的内存分配,或类似的行)。

答案 3 :(得分:23)

如果您正在调用一个返回要处理的数据的函数或一个指示错误的标志(或您已完成),这将非常有用。

类似的东西:

while ((c = getchar()) != EOF) {
    // process the character
}

// end of file reached...

就个人而言,这是一个我不太喜欢的习语,但有时候替代方案更加丑陋。

答案 4 :(得分:10)

如果您无意中尝试将作业用作真值,GCC可以帮助您检测(使用-Wall),以防它建议您编写

if ((n = foo())) {
   ...
}

即。使用额外的括号表示这确实是你想要的。

答案 5 :(得分:8)

当您编写while循环而不是if语句时,这个习惯用法更有用。对于if语句,您可以按照描述进行分解。但是如果没有这种结构,你可能要重复自己:

c = getchar();
while (c != EOF) {
    // ...
    c = getchar();
}

或使用循环半结构:

while (true) {
    c = getchar();
    if (c == EOF) break;
    // ...
}

我通常更喜欢循环形式。

答案 6 :(得分:4)

简短的回答是Expression-oriented编程语言允许更简洁的代码。它们不会强迫您separate commands from queries

答案 7 :(得分:3)

例如,在PHP中,它对于循环SQL数据库结果非常有用:

while ($row = mysql_fetch_assoc($result)) {
    // Display row
}

这看起来好于:

$row = mysql_fetch_assoc($result);
while ($row) {
    // Display row
    $row = mysql_fetch_assoc($result);
}

答案 8 :(得分:2)

另一个优势在于使用gdb。 在以下代码中,如果我们单步执行,则不知道错误代码。

while (checkstatus() != -1) {
    // process
}

相反

while (true) {
    int error = checkstatus();
    if (error != -1)
        // process
    else
        //fail
}

现在,在单步骤中,我们可以知道checkstatus()的返回错误代码是什么。

答案 9 :(得分:0)

我发现它对于返回可选值(在C ++ 17中为boost::optionalstd::optional)的函数非常有用:

std::optional<int> maybe_int(); // function maybe returns an int

if (auto i = maybe_int()) {
    use_int(*i);
}

这缩小了变量的范围,使代码更紧凑,并且不妨碍可读性(我发现)。

与指针相同:

int* ptr_int();

if (int* i = ptr_int()) {
    use_int(*i);
}

答案 10 :(得分:0)

我今天在用 Arduino(C 语言)编程时使用了它。

案例

我有一个发射器和一个接收器。 发送器想要发送数据,直到它被接收。我想在进程完成后设置一个标志。

while (!(newtork_joined = transmitter.send(data))) {
Serial.println("Not Joined");
}

这里:

  • "transmitter.send" - 传输成功时返回真
  • “newtork_joined” - 是我成功时设置的标志

结果

  1. 传输不成功时不设置标志,循环为真时继续执行

  2. 成功时设置标志,循环失败时退出

<块引用>

漂亮吗?

答案 11 :(得分:-2)

原因是:

  1. 绩效改善(有时)

  2. 较小的代码(始终)

  3. 举一个例子:有一个方法someMethod(),并且在if条件下,您要检查方法的返回值是否为null。如果不是,您将再次使用返回值。

    If(null != someMethod()){
        String s = someMethod();
        ......
        //Use s
    }
    

    由于您两次调用相同的方法,因此会妨碍性能。而是使用:

    String s;
    If(null != (s = someMethod())) {
        ......
        //Use s
    }