Почему вы используете назначение в условии? - PullRequest
67 голосов
/ 30 сентября 2008

На многих языках задания законны по условиям. Я никогда не понимал причину этого. Почему вы пишете:

if (var1 = var2) {
  ...
}

вместо:

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

Ответы [ 10 ]

98 голосов
/ 30 сентября 2008

Это более полезно для циклов, чем для операторов.

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

Что в противном случае должно было бы быть написано

var = GetNext();
while( var )
{
 ...do something
 var = GetNext();
}
29 голосов
/ 30 сентября 2008

Я считаю это наиболее полезным в цепочках действий, которые часто связаны с обнаружением ошибок и т. Д.

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() - конечно, а не просто проверками. То есть они могут быть проверены этапами процесса, которым управляет функция. (Чаще всего в коде, с которым я работаю, функции выполняются в соответствии с проверками предварительных условий или выделением памяти, необходимой для работы функции, или в аналогичных строках).

29 голосов
/ 30 сентября 2008

Это более полезно, если вы вызываете функцию:

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

Конечно, вы можете просто поставить n = foo (); в отдельном утверждении тогда if (n), но я думаю, что вышеизложенное является довольно читабельной идиомой.

23 голосов
/ 30 сентября 2008

Это может быть полезно, если вы вызываете функцию, которая возвращает либо данные для работы, либо флаг, указывающий на ошибку (или что вы сделали).

Что-то вроде:

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

// end of file reached...

Лично я не очень люблю эту идиому, но иногда альтернатива более уродлива.

10 голосов
/ 30 сентября 2008

GCC может помочь вам определить (с -Wall), если вы непреднамеренно пытаетесь использовать назначение в качестве значения истинности, в случае, если вам рекомендуется написать

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

т.е. используйте лишние скобки, чтобы указать, что это действительно то, что вы хотите.

8 голосов
/ 30 сентября 2008

Эта идиома более полезна, когда вы пишете цикл while вместо оператора if. Для оператора if вы можете разбить его, как вы описываете. Но без этой конструкции вам придется либо повторить себя:

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

или используйте структуру с полукруглой структурой:

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

Я обычно предпочитаю полукруглую форму.

4 голосов
/ 30 сентября 2008

Короткий ответ таков: Языки программирования, ориентированные на выражения , позволяют использовать более сжатый код. Они не заставляют вас отделять команды от запросов .

3 голосов
/ 30 сентября 2008

Например, в PHP это полезно для циклического просмотра результатов базы данных SQL:

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

Это выглядит намного лучше, чем:

$row = mysql_fetch_assoc($result);
while ($row) {
    // Display row
    $row = mysql_fetch_assoc($result);
}
2 голосов
/ 10 октября 2013

Другое преимущество приходит во время использования GDB. В следующем коде код ошибки не известен, если бы мы были на один шаг.

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

Скорее

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

Теперь на одном шаге мы можем узнать, какой был код ошибки возврата из checkstatus ().

0 голосов
/ 18 ноября 2016

Причина:

  1. Улучшение производительности (иногда)

  2. Малый код (всегда)

Возьмем пример: есть метод someMethod(), и в условии if вы хотите проверить, является ли возвращаемое значение метода null. Если нет, вы собираетесь использовать возвращаемое значение снова.

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

Это снизит производительность, так как вы вызываете один и тот же метод дважды. Вместо этого используйте:

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