Почему я не могу использовать ?: операторы в третьем аргументе цикла for в Java?

Вы должны передать массив InputPhoneContact в ImportContactsRequest, как следует из документации:

https://lonamiwebs.github.io/Telethon/methods/contacts/import_contacts.html

Этот код должен работать:

try: 
contact = InputPhoneContact(client_id = 0, phone = "+" + line, first_name="ABC", last_name="abc")            
result = client(functions.contacts.ImportContactsRequest([contact]))

29
задан 17.05.2020, 07:34

4 ответа

Это потому, что цикл for был определен таким образом в Спецификации языка Java .

14.14.1 Базовый для оператора

BasicForStatement:
    for ( ForInit ; Expression ; ForUpdate ) Statement

ForStatementNoShortIf:
    for ( ForInit ; Expression ; ForUpdate ) StatementNoShortIf

ForInit:
    StatementExpressionList
    LocalVariableDeclaration

ForUpdate:
    StatementExpressionList


StatementExpressionList:
    StatementExpression
    StatementExpressionList , StatementExpression

Таким образом, он должен быть StatementExpression или кратным StatementExpression с, а StatementExpression определяется как:

14.8 Операторы выражений

StatementExpression:
    Assignment
    PreIncrementExpression
    PreDecrementExpression
    PostIncrementExpression
    PostDecrementExpression
    MethodInvocation
    ClassInstanceCreationExpression

0 <= n ? (i++) : (i--) не относятся к числу таких, поэтому они не принимаются. i += ((0 <= n) ? 1 : -1) - это задание, поэтому оно работает.

47
ответ дан 17.05.2020, 07:37
  • 1
    Кроме того, выбранный случайный порт, как гарантируют, будет пронумерован выше 1024, поскольку диапазон 1-1024 резервируется для определенных важных услуг, таких как HTTP (S), FTP, DNS, и т.д. – alastairs 11.10.2019, 06:35
  • 2
    Я ценю, что кто-то занял время для заключения в кавычки спецификации. Но Вы знаете , почему это - этот путь? Это не , почему , это как . Как высказывание: " Это повышает ошибку, потому что это реализовано тот путь в источнике " – jdm 17.05.2020, 07:37
  • 3
    @jdm я действительно думаю, что это почему , но you' ре, корректное в этом, которым, вероятно, состоял бы в том следующий вопрос, почему это будет определено этот путь. Я думаю, что этому в значительной степени уже ответили Eric все же. – eis 17.05.2020, 07:38
  • 4
    Я был так рад видеть ответ на этот вопрос путем показа грамматики спецификации языка. Существует надежда, оставленная в этом мире. Спасибо за восстановление моей веры в человечество, @eis. – alvonellos 17.05.2020, 07:38

заменить

0 <= n ? (i++) : (i--)

на

i += ((0 <= n) ? 1 : -1)

, которые должны работать

17
ответ дан 17.05.2020, 07:35
  • 1
    Клиент СОЕДИНИТСЯ с портом 80 на сервере, но будет использовать другой порт сам. Попробуйте его сами: загрузите файл с сервера (например, видео YouTube), откройте подсказку и введите " netstat". Ваша собственная машина будет использовать случайный порт (как 62 123) для соединения с сервером на порте 80. – Konerak 11.10.2019, 06:35
  • 2
    - 1 для дампа кода без объяснения. " Сделайте это и это, и это будет work" не хороший совет дать для ученика/новичка. You' ре, поощряющее его скопировать/вставить кодировать произвольно, на самом деле не понимая его. – Doorknob 17.05.2020, 07:35
  • 3
    +1. Тернарные операторы должны обычно возвращать значение, не изменяя его источник (который сделан с i-- или i++). – John WH Smith 17.05.2020, 07:35
  • 4
    В то время как это - хороший совет, это doesn' t действительно отвечают на вопрос , почему этот синтаксис (который работает отлично, например, в C и JavaScript) должен быть недопустимым в Java. – Ilmari Karonen 17.05.2020, 07:36

Ваш код выдает ошибку в основном из-за того, что вы пытаетесь решить свою проблему с помощью неверного алгоритма. Тот факт, что JLS не допускает использование троичного в качестве условия в для цикла , также не помогает - но главная проблема в том, что вы упускаете правильное решение задачи.

Давайте начнем с общего утверждения, prematureOptimization == sqrt(sum(evil)) - сначала вы должны рассмотреть , что вы хотите сделать, а не , как это сделать или , почему код не работает.

  • цикл должен просто выполняться n раз, используя i в качестве счетчика.
  • Шаг i должен быть равен 1, если n равно> = 0, в противном случае -1

    ( примечание: если n является инвариантом (и он здесь) с использованием, например, abs (n) или n < 0 в условии, это плохая практика, хотя большинство компиляторов будет пытаться вычленить инвариант из цикла, обычно следует просто используйте временную переменную для хранения результата и вместо этого используйте результат в сравнении)

Итак, код под рукой должен быть:

void doSomething( int n ) {
  if ( n >= 0 )
    for( int i = 0; i < n; i++ )
      f( i, n );
  else
    for( int i = 0; i > n; i-- )
      f( i, n );
}

Факторинг из инвариантов и разделение отдельных ветвей кода - основные методы, используемые для повышения эффективности алгоритмов (не преждевременная оптимизация , обратите внимание); нет более быстрого и чистого способа сделать это. Некоторые могут возразить, что это случай разматывания петли - это очень хорошо было бы , если бы не тот факт, что эти две петли не должны быть намотаны вместе в первую очередь .. . [1 125]

Другое дело: третья операция в для цикла всегда была обычным оператором; давайте попробуем угадать , почему следующий код не компилируется?

0 <= n ? (i++) : (i--); // error: not a statement

... может быть, потому что следующий код тоже не скомпилируется?

0 <= n ? i : i; // error: not a statement

... и это по той же причине, что приведенный ниже код не будет работать и в Java?

i; // error: not a statement

Ваш ответ: ternary - это не утверждение - ternary просто возвращает значение и значение не является оператором ( по крайней мере в Java ); i++ и i-- разрешены в троичной форме только потому, что они возвращают значение , но они также вызывают побочные эффекты здесь.

4
ответ дан 17.05.2020, 07:35
  • 1
    Но что, если мой клиент/сервер связывается на 80..., если клиент получает сообщение на порте 80 (почему) won' t браузер прерывают его как содержание HTTP? – Mr. Boy 11.10.2019, 06:34
  • 2
    +1 для извлечения двух совершенно других случаев в отдельные циклы. этот ответ должен быть путем там с Eric' s, как it' s самый чистый способ решить задачу под рукой. It' удобный в сопровождении s и оптимизатор может легко понять структуру циклов, делая его эффективным без микрооптимизации – Silly Freak 17.05.2020, 07:36

Прежде всего, я бы рекомендовал не писать код таким способом. Целью кода является «считать от нуля до n, если n положительно, считать от 0 до n, если n отрицательно», но я бы вместо этого написал:

for (int i = 0; i < abs(n); i += 1)
{
    int argument = n < 0 ? -i : i;
    f(argument, n);
}

Но это не отвечает на ваш вопрос, а именно:

Почему я не могу использовать операторы ?: в третьем аргументе для циклов for в Java?

A for петля имеет структуру for ( initialization ; condition ; action ).

Целью выражения является вычисление значения.

Цель заявления - предпринять действие.

Существуют некоторые выражения, которые по замыслу одновременно вычисляют значение и выполняют действие. i++, i += j, new foo(), method() и так далее.

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

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

По сути, запретив этот код, компилятор говорит вам, что вы сделали неудачный стилистический выбор. b?i++:i-- является допустимым выражением, но это действительно плохой стиль, потому что он превращает то, что предполагается , вычисляя значение в , создавая побочный эффект и игнорируя значение . [1 125]

23
ответ дан 17.05.2020, 07:36
  • 1
    @John, нет. веб-сервер открывает порт 80, но браузер имеет различный, случайным-образом-назначенный-порт. Если Ваше приложение связывается на порте 80 тогда, Вы препятствуете тому, чтобы Ваше приложение использовалось на той же машине в качестве веб-сервера, но Вас don' t вмешиваются вообще в просмотр веб-страниц. – JSBձոգչ 11.10.2019, 06:35
  • 2
    (не говоря уже об ужасном я + = 1 Вы использовали... what' s неправильно со мной ++ в наше время?) – vaxquis 17.05.2020, 07:36
  • 3
    Истина @vaxquis быть сказанным, если Вы заботитесь о производительности, I' m не уверенный, почему you' d устраняют временные переменные, и все же компиляция с нулевой оптимизацией переключают или предназначаются для времени выполнения с Дрожанием неоптимизации. Кроме этого, удобочитаемость выпускает Вас, упоминание очевидно абсолютно субъективно, и у всех может быть их собственное мнение об этом, так как я знаю много людей (большинство людей, на самом деле), кто находит, что долгий идентификатор называет более читаемым (главным образом, потому что в больших платформах у них есть шанс устранения времени поиска в документации платформы). – Theodoros Chatzigiannakis 17.05.2020, 07:37
  • 4
    Путь you' d быть склонным записать плохая практика кодирования; you' ve два инварианта, которые обрабатываются с каждым повторением цикла, а именно, брюшной пресс (n) и n < 0; кроме того, Вы don' t должны использовать временный файл в этом случае, встраивая аргумент " f (n < 0?-i: я; n) " wouldn' t вред вообще здесь. Если f () является быстрым методом, и n достаточно высок, you' d повредить эффективность серьезно. – vaxquis 17.05.2020, 07:37
  • 5
    @vaxquis: Прежде всего у Вас, по-видимому, есть общая, но странная вера, что устранение имени, связанного с временной ценностью так или иначе, делает его " better". я не уверен, куда эта странная вера прибывает из. Эта вера выравнивается по ширине доказательством, или Вы просто утверждаете его? – Eric Lippert 17.05.2020, 07:38
  • 6
    @vaxquis: Во-вторых, я являюсь беззаботным по отношению к нескольким дополнительным наносекундам, понесенным ненужными вычислениями в цикле. Хороший оптимизатор обнаружит инварианты цикла и поднимет их. Но в более общем плане: это - плохая практика для нанооптимизирования программы без направленного на профиль доказательства. Вручную спускоподъемные инварианты цикла в C# могут на самом деле заставить дрожание генерировать медленнее код. Необходимо записать код, чтобы быть максимально ясными, и затем проверить, что он удовлетворяет целям производительности. – Eric Lippert 17.05.2020, 07:38

Теги

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