Помимо синтаксических различий, являются ли они по сути одинаковыми? Оба они реализованы на основном языке? или foreach часть стандартной библиотеки? Что же касается производительности, то это имеет значение, если я выбираю один за другим?
For и foreach в D
Ответ 1
Вы всегда должны использовать foreach, если это возможно.
-
foreachперебирать практически все (даже метаданные, такие как типы данных времени компиляции);forне может.foreach (Type; TypeTuple!(int, long, short)) { pragma(msg, Type); }но вы не можете сделать это с помощью цикла
for. -
foreachможет использоваться для выполнения действий во время компиляции (расширение выше); например, если у вас есть фрагмент кода, который повторяется 10 раз, вы можете сказать:template Iota(size_t a, size_t b) //All integers in the range [a, b) { static if (a < b) { alias TypeTuple!(a, Iota!(a + 1, b)) Iota; } else { alias TypeTuple!() Iota; } } foreach (i; Iota!(0, 10)) { int[i] arr; } //Not possible with 'for'и это будет во время компиляции, причем
iрассматривается как константа . (Обычно это не работает сfor.) -
foreachможет быть перегружен с помощьюopApply, а также с конструкциями диапазона, ноforне может. Это очень удобно при итерации древовидной структуры (например, всех папок в файловой системе), поскольку фактически позволяет использовать полностью стекную память, а не выделять кучу (потому что вы можете использовать рекурсии). -
foreachявляется предпочтительным в большинстве ситуаций, поскольку он предотвращает необходимость ввода ваших данных в явном виде, что полезно для предотвращения некоторых ошибок. Например,for (int i = 0; i < n; i++) { arr[i]++; }опасно, если
nбольше 2 ^ 32 - 1, ноforeach (i; 0 .. n) { arr[i]++; }нет, потому что компилятор автоматически выбирает правильный тип для итерации. Это также улучшает читаемость.
Ответ 2
Основное различие между foreach и for - это более высокий уровень
абстракция a foreach -loop. A foreach -loop обычно понижается до некоторого
for -loop компилятором. Это имеет (по крайней мере) четыре преимущества:
- Читаемость:
foreach (a; someArray) doSomething(a);по своей сути больше чемfor (size_t i = 0; i < someArray.length; i++) doSomething(someArray[i]);. Это становится еще яснее, если типsomeArrayне является простым массивом. - Гибкость: если в какой-то момент вы решите, что тип
someArrayнеобходимо изменить из некоторого массива, скажем, в диапазон или объект (например, для реализации параллельного цикла),foreachостается неизменным, тогда какfor-loop следует изменить, чтобы использовать либоempty,front, иpopFront(в случае диапазона) илиopApplyили какой-либо другой механизм в случае класса или структуры. - Специальные функции. итерация по типам кортежей, декодирование UTF-8 и Строки UTF-16.
- Производительность:
foreach-loop позволяет компилятору решить, как оптимально реализовать цикл на основе типа (итерации по массиву, диапазону, строка, объект...) и, возможно, другую информацию (например, размер тип). Это обеспечивает эффективную реализацию для всех типов и другого компилятора оптимизация без необходимости слишком беспокоиться о реализации Детали. В действительности производительностьforeachотносительно ручной кодировкиforсмешивается.foreach(dchar c; someString) {...}(т.е. декодирование UTF-8 string while looping) очень быстро. Ноforeach(a; someObject) {...}, гдеsomeObjectреализуетopApply, немного медленнее (поскольку тело цикла завернутый в делегат, и opApply обычно вызывает этот делегат внутри цикла, который генерирует некоторые накладные расходы). Как обычно, это не имеет значения для вашего кода в 99,99% случаи, так какforeachвсегда будет давать (по крайней мере) приличную реализацию.
Основной недостаток (к тому же, иногда, скорость) заключается в том, что некоторые вещи не могут
выполняются с помощью foreach, а именно: многие мутации вещи, зацикленной над
(например, изменение размера массива внутри тела цикла).