Назначение переменной в & ldquo; if & rdquo; состояние [дубликат]

Метод seq является самым простым, но у Bash есть встроенная арифметическая оценка.

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

Конструкция for ((expr1;expr2;expr3)); работает так же, как for (expr1;expr2;expr3) на C и подобных языках, и нравится других ((expr)) случаях, Bash рассматривает их как арифметику.

29
задан Adrian McCarthy 16 July 2013 в 20:10
поделиться

7 ответов

if (Derived* derived = dynamic_cast<Derived*>(base)) {
   // do stuff with `derived`
}

Хотя это часто упоминается как антишаблон («использовать виртуальную рассылку!»), Иногда тип Derived обладает функциональностью, которой просто не обладает Base (и, следовательно, отдельными функциями), и это хороший способ включить эту семантическую разницу.

37
ответ дан Lightness Races in Orbit 16 July 2013 в 20:10
поделиться

Оператор присваивания возвращает значение назначенного значения . Итак, я мог бы использовать его в такой ситуации:

if(x = getMyNumber())

Затем я присваиваю x значение, возвращаемое getMyNumber, и проверяю, не равен ли он нулю.

Избегайте этого, я привел вам пример, чтобы помочь вам понять это.

Редактировать: добавление Просто предложение (может понравиться).

Чтобы избежать таких ошибок, вплоть до некоторых расширений, нужно записать условие if как if(NULL == ptr) вместо if(ptr == NULL), потому что при неправильном написании оператора проверки равенства == в качестве оператора =, компиляция выдаст ошибку lvalue с if(NULL = ptr), но if(res = NULL), переданную компилятором (что вы не имеете в виду), и останется ошибкой в ​​коде для среды выполнения.
По той же причине я предпочитаю писать if(getMyNumber() ==x) вместо if(x == getMyNumber())

Следует также читать: Критика в отношении этого вида кода.

12
ответ дан Grijesh Chauhan 16 July 2013 в 20:10
поделиться

Я столкнулся с случаем, когда это было полезно совсем недавно, поэтому я решил опубликовать его.

Предположим, вы хотите проверить несколько условий в одном if, и если какое-либо из условий выполняется, вы хотите сгенерировать сообщение об ошибке. Если вы хотите включить в свое сообщение об ошибке, какое конкретное условие вызвало ошибку, вы можете сделать следующее:

std::string e;
if( myMap[e = "ab"].isNotValid() ||
    myMap[e = "cd"].isNotValid() ||
    myMap[e = "ef"].isNotValid() )
{
    // here, e has the key for which the validation failed
}

Так что, если второе условие является тем, которое оценивается как true, e будет равно " CD". Это связано с поведением короткого замыкания в ||, которое предписано стандартом (если не перегружено). См. этот ответ для более подробной информации о коротком замыкании.

5
ответ дан Community 16 July 2013 в 20:10
поделиться

Это зависит от того, хотите ли вы писать чистый код или нет. Когда C впервые разрабатывался, важность чистого кода не была полностью осознана, и компиляторы были очень просты: использование подобного вложенного назначения часто могло привести к более быстрому коду. Сегодня я не могу вспомнить ни одного случая, когда хороший программист сделал бы это. Это просто делает код менее читаемым и более сложным в обслуживании.

9
ответ дан James Kanze 16 July 2013 в 20:10
поделиться

почему компилятор не выдает предупреждение

Некоторые компиляторы будут генерировать предупреждения для подозрительных назначений в условном выражении, хотя обычно вам нужно включить предупреждение явно.

Например, в Visual C ++ необходимо включить C4706 (или предупреждения уровня 4 в целом). Я обычно включаю как можно больше предупреждений и делаю код более явным, чтобы избежать ложных срабатываний. Например, если бы я действительно хотел сделать это:

if (x = Foo()) { ... }

Тогда я бы написал это как:

if ((x = Foo()) != 0) { ... }

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

Единственный недостаток этого подхода - то, что вы не можете использовать его, когда переменная объявлена ​​в условии. То есть вы не можете переписать:

if (int x = Foo()) { ... }

как

if ((int x = Foo()) != 0) { ... }

Синтаксически, это не работает. Таким образом, вы должны либо отключить предупреждение, либо пойти на компромисс в отношении того, насколько плотно вы работаете x.

ОБНОВЛЕНИЕ: В C ++ 17 добавлена ​​возможность иметь оператор init в условии для оператора if ( p0305r1 ), что хорошо решает эту проблему (для вида сравнения, а не только != 0).

if (x = Foo(); x != 0) { ... }

Кроме того, если вы хотите, вы можете ограничить область действия x только выражением if:

if (int x = Foo(); x != 0) { /* x in scope */ ... }
// x out of scope
3
ответ дан danger89 16 July 2013 в 20:10
поделиться

Вот немного истории о синтаксисе, о котором идет речь.

В классическом C обработка ошибок часто выполнялась путем написания чего-то вроде:

int error;
...
if(error = foo()) {
    printf("An error occured: %s\nBailing out.\n", strerror(error));
    abort();
}

Или, когда был вызов функции, который мог бы вернуть нулевой указатель, идиома использовалась наоборот:

Bar* myBar;
... //in old C variables had to be declared at the start of the scope
if(myBar = getBar()) {
    //do something with myBar
}

Однако этот синтаксис опасно близок к

if(myValue == bar()) ...

, поэтому многие люди считают присвоение внутри условия плохим стилем, и компиляторы начали предупреждать об этом (по крайней мере, с -Wall). Однако этого предупреждения можно избежать, добавив дополнительный набор скобок:

if((myBar = getBar())) {  //tells the compiler: Yes, I really want to do that assignment!

Затем появился C99, позволяющий смешивать определения и утверждения, поэтому многие разработчики часто пишут что-то вроде

Bar* myBar = getBar();
if(myBar) {

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

if(Bar* myBar = getBar()) {

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

if(Bar* myBar = getBar()) {
    ...
}
foo(myBar->baz);  //compiler error
//or, for the C++ enthusiasts:
myBar->foo();     //compiler error

Без определения переменной внутри оператора if это условие не будет обнаружено.

Короче говоря, длинный ответ: синтаксис в вашем вопросе является продуктом простоты и мощи старого Си, но это зло, поэтому компиляторы могут предупредить об этом. Поскольку это также очень полезный способ выражения общей проблемы, теперь существует очень лаконичный и надежный способ добиться того же поведения. И есть много хороших, возможных применений для этого.

24
ответ дан cmaster 16 July 2013 в 20:10
поделиться

Выполнение задания в if является довольно распространенной вещью, хотя также часто люди делают это случайно.

Обычный шаблон:

if (int x = expensive_function_call())
{
  // ...do things with x
}

Анти-шаблон - это то, где вы ошибочно назначаете вещи:

if (x = 1)
{
  // Always true
}
else
{
  // Never happens
}

Вы можете избежать этого до некоторой степени поставив сначала свои константы или значения const, ваш компилятор выдаст ошибку:

if (1 = x)
{
  // Compiler error, can't assign to 1
}

= против == - это то, что вам нужно для развития. Я обычно ставлю пробел вокруг оператора, чтобы было более очевидно, какая операция выполняется, поскольку longname=longername выглядит очень похоже на longname==longername, но сами по себе = и ==, очевидно, различаются.

1
ответ дан tadman 16 July 2013 в 20:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: