В чем разница между циклом for и for-in в Dart?

«В чем разница между циклом for и for-in в Dart?» — вопрос из категории Dart Core, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Классический цикл for

  • Даёт полный контроль над индексом итерации.
  • Позволяет задавать произвольное условие продолжения и шаг.
  • Идеален, когда нужен доступ к индексу элемента или нестандартная логика перебора.
List<String> names = ['Alice', 'Bob', 'Charlie'];

// 1. Доступ по индексу
for (int i = 0; i < names.length; i++) {
  print('$i: ${names[i]}'); // Вывод: "0: Alice", "1: Bob", "2: Charlie"
}

// 2. Итерация с шагом
for (int i = 0; i < names.length; i += 2) {
  print(names[i]); // Вывод: "Alice", "Charlie"
}

// 3. Обратный порядок
for (int i = names.length - 1; i >= 0; i--) {
  print(names[i]); // Вывод: "Charlie", "Bob", "Alice"
}

Цикл for-in

  • Предназначен для лаконичного перебора элементов коллекции (Iterable).
  • Не предоставляет доступа к индексу «из коробки».
  • Читается проще и меньше подвержен ошибкам (например, выходу за границы массива).
for (var name in names) {
  print(name); // Вывод: "Alice", "Bob", "Charlie"
}

// for-in с Map:
Map<String, int> scores = {'Alice': 100, 'Bob': 85};
for (var entry in scores.entries) {
  print('${entry.key}: ${entry.value}');
}

Как получить индекс в for-in? Используйте метод .asMap() или статический метод List.generate.

// Способ 1: asMap()
for (var entry in names.asMap().entries) {
  print('${entry.key}: ${entry.value}');
}

// Способ 2: List.generate (если нужно сразу преобразовать)
List<String> indexedNames = List.generate(
  names.length,
  (index) => '$index: ${names[index]}',
);

Выбор цикла:

  • Используйте for-in для простого перебора всех элементов.
  • Используйте классический for, когда критически важен индекс, нужен обратный порядок или нестандартный шаг.