Skip to content

Break и continue

При работе с циклами в Dart часто возникает необходимость изменить стандартное поведение цикла: прервать его выполнение досрочно или пропустить определенную итерацию. Для этих целей служат операторы break и continue.

Оператор break

!break

Оператор break используется для немедленного завершения выполнения цикла. Когда выполнение кода доходит до break, происходит выход из текущего цикла, и программа продолжает выполняться с первой инструкции после цикла.

В цикле for

for (int i = 0; i < 10; i++) {
  if (i == 5) {
    break; // Завершаем цикл, когда i достигнет 5
  }
  print(i);
}
print('Цикл завершен');

Вывод:

0
1
2
3
4
Цикл завершен

Или другой пример

for (int i = 0; i < 100; i++) {
  if (i * i > 200) {
    print('Первое число, квадрат которого больше 200: $i');
    break;
  }
}

В цикле while

int counter = 0;
while (true) { // Бесконечный цикл
  counter++;
  if (counter > 10) {
    break; // Выходим из цикла после 10 итераций
  }
  print('Итерация $counter');
}

В циклах do-while

int i = 0;
do {
  i++;
  print('Значение i: $i');
  if (i >= 5) {
    break;
  }
} while (i < 10);

Break с метками

В Dart можно использовать break с метками для выхода из вложенных циклов.

outerLoop: for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 3; j++) {
    if (i == 1 && j == 1) {
      break outerLoop; // Выход из обоих циклов
    }
    print('i = $i, j = $j');
  }
}

Оператор continue

Оператор continue используется для пропуска оставшейся части текущей итерации цикла и перехода к следующей итерации.

for (int i = 0; i < 5; i++) {
  if (i == 2) {
    continue; // Пропускаем итерацию, когда i равно 2
  }
  print('Значение i: $i');
}

Вывод:

Значение i: 0
Значение i: 1
Значение i: 3
Значение i: 4

Применение в различных типах циклов

В цикле for

for (int i = 1; i <= 10; i++) {
  if (i % 2 == 0) {
    continue; // Пропускаем четные числа
  }
  print('Нечетное число: $i');
}

В цикле while

int i = 0;
while (i < 10) {
  i++;
  if (i % 3 == 0) {
    continue; // Пропускаем числа, кратные 3
  }
  print('Число не кратно 3: $i');
}

В циклах do-while

int i = 0;
do {
  i++;
  if (i % 4 == 0) {
    continue; // Пропускаем числа, кратные 4
  }
  print('Значение, не кратное 4: $i');
} while (i < 10);

Continue с метками

Как и break, оператор continue может использоваться с метками для управления вложенными циклами.

outerLoop: for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 3; j++) {
    if (j == 1) {
      continue outerLoop; // Переходим к следующей итерации внешнего цикла
    }
    print('i = $i, j = $j');
  }
}

Пример обработки пользовательского ввода

import 'dart:io';
 
void main() {
  while (true) {
    print('Введите команду (exit для выхода):');
    String? input = stdin.readLineSync();
 
    if (input == null || input.isEmpty) {
      print('Пустой ввод, попробуйте снова.');
      continue;
    }
 
    if (input.toLowerCase() == 'exit') {
      print('Выход из программы.');
      break;
    }
 
    print('Вы ввели: $input');
  }
}

Критика и альтернативные подходы

Противоречия с принципами структурного программирования

С точки зрения структурного программирования операторы break и continue часто вызывают споры. Эдсгер Дейкстра и другие теоретики программирования считают, что их использование может указывать на недостаточно проработанный алгоритм решения задачи. Они относят эти операторы к неструктурным средствам, подобным безусловным переходам (goto), и утверждают, что любая логика с их применением может быть переписана более структурированным способом.

Альтернативные решения

Вот как можно переписать некоторые из приведенных выше примеров без использования break и continue:

Вместо break:

// С использованием break
for (int i = 0; i < 10; i++) {
  if (i == 5) {
    break;
  }
  print(i);
}
 
// Альтернатива без break
for (int i = 0; i < 10 && i < 5; i++) {
  print(i);
}

Вместо continue:

// С использованием continue
for (int i = 0; i < 5; i++) {
  if (i == 2) {
    continue;
  }
  print('Значение i: $i');
}
 
// Альтернатива без continue
for (int i = 0; i < 5; i++) {
  if (i != 2) {
    print('Значение i: $i');
  }
}

Баланс между практичностью и чистотой кода

Несмотря на теоретическую критику, в современной разработке break и continue остаются полезными инструментами:

  1. Они могут сделать код более читаемым в определенных сценариях
  2. Могут повысить производительность, избавляя от ненужных итераций
  3. Являются общепринятыми конструкциями, понятными большинству разработчиков

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

Лучшие практики и рекомендации

  1. Используйте break для раннего выхода из цикла, когда условие выполнено, чтобы избежать ненужных итераций.

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

  3. Избегайте злоупотребления метками — они могут сделать код трудным для понимания. Используйте их только когда это действительно необходимо.

  4. Старайтесь не использовать бесконечные циклы (while (true)) без явного условия выхода с помощью break.

  5. Учитывайте контекст — в простых случаях функциональный подход может быть лучше, но в сложных сценариях императивный стиль с break/continue может быть более понятным.

Заключение

Операторы break и continue — практичные инструменты управления потоком выполнения в циклах Dart. Хотя они и критикуются с точки зрения строгого структурного программирования, их разумное применение может привести к более читаемому и эффективному коду. В то же время важно знать о функциональных альтернативах и взвешенно выбирать наиболее подходящий подход для каждой конкретной задачи.

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

Домашнее задание

Задачи на закрепление материала по операторам break и continue в Dart.

1. Сумма до первого отрицательного числа

Задача: Дан список целых чисел. Необходимо найти сумму элементов списка до тех пор, пока не встретится первое отрицательное число. Если отрицательных чисел нет, вернуть сумму всех элементов.

calculateSumUntilNegative([1, 2, 3, -4, 5]) -> 6
calculateSumUntilNegative([1, 2, 3, 4, 5]) -> 15

2. Поиск первого четного числа, кратного 3

Задача: Дан список целых чисел. Необходимо найти первое четное число, которое также кратно 3. Если такого числа нет, вернуть null.

findFirstEvenDivisibleByThree([1, 2, 3, 4, 6, 8]) -> 6
findFirstEvenDivisibleByThree([1, 2, 5, 7, 11]) -> null

3. Пропуск чисел, кратных 5

Задача: Дан список целых чисел. Необходимо вывести на экран все числа из списка, кроме тех, которые кратны 5.

printNumbersNotDivisibleByFive([1, 5, 12, 15, 20, 22]) -> "1 12 22"

4. Подсчет символов до определенного символа

Задача: Дана строка. Необходимо подсчитать количество символов до первого вхождения определенного символа (например, 'x'). Если символ не найден, вернуть длину строки.

countCharactersUntilSymbol("abcdefxgh", "x") -> 6
countCharactersUntilSymbol("abcdefgh", "x") -> 8

5. Обработка пользовательского ввода с проверкой на выход

Задача: Написать программу, которая запрашивает у пользователя ввод строк до тех пор, пока пользователь не введет "exit". После каждого ввода выводить сообщение "Введено: [ввод]".

// Пример взаимодействия с пользователем:
// Введите строку: hello
// Введено: hello
// Введите строку: world
// Введено: world
// Введите строку: exit
// Выход из программы.
22 февр. 2025 г.
andron13