для и foreach заявления в D - PullRequest
       1

для и foreach заявления в D

15 голосов
/ 12 апреля 2011

Помимо синтаксических различий, являются ли эти два по своей сути одинаковыми?Они оба реализованы на базовом языке?или foreach является частью стандартной библиотеки?А что касается производительности, имеет ли значение, если я выберу одно из другого?

Ответы [ 2 ]

15 голосов
/ 12 апреля 2011

Вы всегда должны использовать foreach, если это возможно.

  1. foreach перебирать практически что угодно (даже метаданные, такие как типы данных во время компиляции);for не может.

    foreach (Type; TypeTuple!(int, long, short)) { pragma(msg, Type); }
    

    , но вы не можете сделать это с помощью петли for.

  2. 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.)

  3. foreach может быть перегружено с помощью opApply, а также с конструкциями диапазона, но for не может.Это очень удобно при итерации древовидной структуры (как и все папки в файловой системе), потому что фактически позволяет использовать полностью основанную на стеке память вместо выделения в куче(потому что вы можете использовать рекурсию).

  4. foreach предпочтительнее в большинстве ситуаций, потому что это предотвращает необходимость явного ввода данных, что полезно для предотвращения некоторых ошибок.Например,

    for (int i = 0; i < n; i++) { arr[i]++; }
    

    опасно, если n больше 2 ^ 32 - 1, но

    foreach (i; 0 .. n) { arr[i]++; }
    

    нет, потому что компилятор автоматически выбирает правильный тип для итерации,Это также улучшает читаемость.

10 голосов
/ 12 апреля 2011

Основная разница между foreach и for заключается в более высоком уровне абстракция foreach -петля. foreach петля обычно снижается до некоторой for - петля компилятором. Это имеет (как минимум) четыре преимущества:

  1. Читабельность : foreach (a; someArray) doSomething(a); по своей природе больше удобочитаемее, чем for (size_t i = 0; i < someArray.length; i++) doSomething(someArray[i]);. Это становится еще понятнее, если тип someArray не является простым массивом.
  2. Гибкость : если в какой-то момент времени вы решите, что тип someArray должен быть изменен с некоторого массива, скажем, на диапазон или объект (например, для реализации параллельного цикла), foreach остается неизменным, тогда как for -loop должен быть изменен для использования empty, front и popFront (в случае диапазона) или opApply, или какой-то другой механизм в случае класс или структура.
  3. Специальные функции , например, перебор типов кортежей, декодирование UTF-8 и Струны UTF-16.
  4. Производительность : петля foreach позволяет компилятору решать, как оптимально реализовать цикл на основе типа (итерации по массиву, диапазон, строка, объект ...) и, возможно, другая информация (например, размер тип). Это обеспечивает эффективную реализацию для всех типов и других компиляторов. оптимизация без необходимости беспокоиться о реализации подробности. На самом деле производительность foreach по отношению к ручному кодированию for смешанный foreach(dchar c; someString) {...} (то есть декодирование UTF-8 Строка во время цикла) очень быстро. Но foreach(a; someObject) {...}, где someObject реализует opApply, немного медленнее (потому что тело цикла обернутый в делегат и opApply обычно вызывает этот делегат внутри цикла, который генерирует некоторые накладные расходы). Как обычно, это не имеет значения для вашего кода в 99,99% в случаях, когда foreach всегда будет давать (как минимум) достойную реализацию.

Основным недостатком (кроме, иногда, скорости) является то, что некоторые вещи не могут быть сделано с foreach, а именно с множеством мутаций зацикливаемой вещи (например, изменение размера массива в теле цикла).

...