Мы можем сделать:
using (Stream s ..)
и
for (int i ...)
Почему мы не можем сделать что-то вроде:
while ((int i = NextNum()) > 0) {..}
Я считаю это очень полезным и разумным.
Мы можем сделать:
using (Stream s ..)
и
for (int i ...)
Почему мы не можем сделать что-то вроде:
while ((int i = NextNum()) > 0) {..}
Я считаю это очень полезным и разумным.
Я не разработчик языка, но я дам ему обоснованное предположение.
Предложение внутри while()
выполняется каждый раз, когда цикл выполняется. (+1 больше времени в конце.) Утверждение int i = NextNum()
объявляет локальную переменную. Вы не можете объявлять локальную переменную более одного раза.
Семантически, имеет смысл, что это должно быть возможно. Фактически, как указано в комментариях, это возможно на других языках. Однако это невозможно в С# без повторной записи некоторых основных правил синтаксиса.
Локальные переменные должны быть объявлены в инструкции. Я считаю, что язык будет разделен таким образом, потому что объявление переменной не выполняется. Когда вы видите строку кода, которая создает переменную и присваивает ей значение, это на самом деле просто ярлык для двух операторов. Из Спецификация 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
.
Не знаю наверняка, но вот мое обоснованное предположение.
Для случая работает, потому что на самом деле имеет 3 части.
Эти 3 пробегают разные количества раз. # 1 запускается только один раз, # 2 запускает число итераций +1 и # 3 выполняется один раз на итерацию. Поскольку # 1 работает только после того, как это красивое и чистое место для определения переменной.
Теперь рассмотрим цикл while. Он имеет только 1 часть, и она запускает каждую итерацию + 1. Так как она запускается каждый раз, это не отличное место для определения переменной, которая обязательно должна быть частью условия. Это вызывает вопросы типа
Я предполагаю, что сложность/двусмысленность является одной из причин, почему это не допускается. Это и, вероятно, никогда не было высоким в списке приоритетов.
В отличие от цикла "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) { ... }
Потому что тогда он определяется на каждой итерации. Цикл for не делает этого. (Таким образом, вы не можете определить его снова после первого цикла. Поскольку он уже существует.)
Нет причин, по которым это невозможно сделать - дизайнеры С# просто решили не допускать этого. Он отлично работает в Perl, например ( "while ((my $i = NextNum()) > 0) {...}" ).
Переменные объявления - это утверждения; цикл 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()) {..}