Подтвердить что ты не робот

Почему мы не можем определить переменную внутри цикла while?

Мы можем сделать:

using (Stream s ..)

и

for (int i ...)

Почему мы не можем сделать что-то вроде:

while ((int i = NextNum()) > 0) {..}

Я считаю это очень полезным и разумным.

4b9b3361

Ответ 1

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

Предложение внутри while() выполняется каждый раз, когда цикл выполняется. (+1 больше времени в конце.) Утверждение int i = NextNum() объявляет локальную переменную. Вы не можете объявлять локальную переменную более одного раза.

Update

Семантически, имеет смысл, что это должно быть возможно. Фактически, как указано в комментариях, это возможно на других языках. Однако это невозможно в С# без повторной записи некоторых основных правил синтаксиса.

Локальные переменные должны быть объявлены в инструкции. Я считаю, что язык будет разделен таким образом, потому что объявление переменной не выполняется. Когда вы видите строку кода, которая создает переменную и присваивает ей значение, это на самом деле просто ярлык для двух операторов. Из Спецификация ECMA-334:

Пример

void F() {
   int x = 1, y, z = x * 2;
}

точно соответствует

void F() {
   int x; x = 1;
   int y;
   int z; z = x * 2;
}

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

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

Цикл for специально разработан для объявления локальной переменной, но вы заметите, что часть объявления выполняется только один раз. Оператор using был специально разработан для объявления локальных переменных (и их удаления). Он также "исполняется" только один раз.

Также считайте, что объявление локальной переменной не возвращает значение - оно не может, поскольку оно позволяет объявлять несколько переменных. Какое значение возвратит этот оператор?

int x = 1, y, z = x * 2;

Вышеприведенный оператор является объявлением локальной переменной. Он состоит из типа и трех локальных переменных-деклараторов. Каждый из них может необязательно включать токен "=" и инициализатор локальной переменной. Чтобы разрешить локальную переменную объявлять таким образом, это означало бы, что вы немного раздвигаете существующую грамматику, так как вам понадобится спецификатор типа, но мандат одного декларатора, чтобы он мог вернуть значение.

Включение этого поведения может также иметь отрицательные побочные эффекты. Учитывайте, что инструкции while и do/while противоположны, но параллельны. Как разработчик языка вы бы также включили оператор do для объявления локальной переменной? Я не вижу в этом возможности. Вы не сможете использовать переменную в теле цикла, потому что она еще не была инициализирована (начиная с первого запуска). Только оператор while будет возможен, но тогда вы бы уничтожили parallelism между операторами while и do.

Ответ 2

Не знаю наверняка, но вот мое обоснованное предположение.

Для случая работает, потому что на самом деле имеет 3 части.

  • Итерационная переменная
  • Условие завершения
  • Приращение

Эти 3 пробегают разные количества раз. # 1 запускается только один раз, # 2 запускает число итераций +1 и # 3 выполняется один раз на итерацию. Поскольку # 1 работает только после того, как это красивое и чистое место для определения переменной.

Теперь рассмотрим цикл while. Он имеет только 1 часть, и она запускает каждую итерацию + 1. Так как она запускается каждый раз, это не отличное место для определения переменной, которая обязательно должна быть частью условия. Это вызывает вопросы типа

  • Должно ли определение выполняться один или один раз на итерацию? Если это последний, сколько людей поймут это неправильно и испортят условное? Если это первый, то у вас есть полная инструкция, из которой только одна часть выполняется один раз за запрос
  • Как ведут себя различные переменные?

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

Ответ 3

В отличие от цикла "for", "while" не имеет части инициализации. Синтаксис "for" выглядит следующим образом:

for ( initializer; conditional expression; loop expression)
{
      statements to be executed
}

и 'while' выглядит так:

while (condition)
{
      statements to be executed
}

Самое близкое к вашему запросу:

int i;
while ((i = NextNum()) > 0) { ... }

Ответ 4

Потому что тогда он определяется на каждой итерации. Цикл for не делает этого. (Таким образом, вы не можете определить его снова после первого цикла. Поскольку он уже существует.)

Ответ 5

Нет причин, по которым это невозможно сделать - дизайнеры С# просто решили не допускать этого. Он отлично работает в Perl, например ( "while ((my $i = NextNum()) > 0) {...}" ).

Ответ 6

Переменные объявления - это утверждения; цикл while ожидает выражения (выражение может быть выражением, но не наоборот). using и for, с другой стороны, являются специальными, чтобы разрешать объявления переменных.

Что еще более важно, масштаб такой вещи будет неясным. Рассмотрим:

int x;
// ...
y = (int x = 42) + x;
// what is y?

Или хуже:

(int x = 42) + (int x = 42);

Или даже:

(int x = 42, y = 24) // what is the value of this expression?

Как только вы разрешаете объявлениям быть выражениями, вам приходится иметь дело с этими вещами. В частности, последний пример становится проблемой, потому что трудно устранить неоднозначность между выражением expression-declaration-as-a-statement или statement-declaration, поэтому стиль выражения должен быть достаточно общим, чтобы быть как заявления операторов.

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

Наконец, вы можете получить то, что хотите, только с помощью цикла for. Например:

while ((int i = NextNum()) > 0) {..}
// becomes...
for (int i; (i = NextNum()) > 0; ) {..}
// or...
for (int i = NextNum(); i > 0; i = NextNum()) {..}