for and foreach statements in D
Besides the synt开发者_如何转开发actic differences, are the two inherently the same? Are both of them implemented in the core language? or is foreach
part of the standard library? And as far as performance, does it make a difference if I choose one over the other?
You should always use foreach
if possible.
foreach
iterate over practically anything (even metadata, like compile-time data types);for
can't.foreach (Type; TypeTuple!(int, long, short)) { pragma(msg, Type); }
but you can't do that with a
for
loop.foreach
can be used to perform actions at compile-time (extension of above); for example, if you have a piece of code that repeats 10 times, you can say: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'
and this will occur at compile-time, with
i
treated as a constant. (This doesn't normally work withfor
.)foreach
can be overloaded withopApply
and also with range constructs, butfor
can't. This is very handy when iterating a tree structure (like all the folders in a file system), because it actually allows you to use entirely stack-based memory rather than allocating on the heap (because you can use recursion).foreach
is preferred in most situations because it prevents the need for you to type your data explicitly, which is useful in preventing some bugs. For example,for (int i = 0; i < n; i++) { arr[i]++; }
is dangerous if
n
is greater than 2^32 - 1, butforeach (i; 0 .. n) { arr[i]++; }
is not, because the compiler automatically chooses the correct type for iteration. This also improves readability.
The main difference between foreach
and for
is the higher level of
abstraction of a foreach
-loop. A foreach
-loop is typically lowered to some
for
-loop by the compiler. This has (at least) four advantages:
- Readability:
foreach (a; someArray) doSomething(a);
is inherently more readable thanfor (size_t i = 0; i < someArray.length; i++) doSomething(someArray[i]);
. This gets even clearer if the type ofsomeArray
is not a simple array. - Flexibility: if, at one point in time, you decide that the type of
someArray
has to be changed from some array to, say, a range or an object (e.g. to implement a parallel loop),foreach
stays unchanged whereas thefor
-loop has to be changed to use eitherempty
,front
andpopFront
(in the case of a range) oropApply
or some other mechanism in the case of a class or struct. - Special features, e.g. iterating over type tuples, decoding of UTF-8 and UTF-16 strings.
- Performance: the
foreach
-loop lets the compiler decide how to optimally implement the loop based on the type (iterating over an array, a range, a string, an object ...) and possibly other information (e.g. the size of the type). This allows for efficient implementation for all types and other compiler optimizations without you having to worry too much about implementation details. In reality, the performance offoreach
relative to hand-codedfor
is mixed.foreach(dchar c; someString) {...}
(i.e. the decoding of an UTF-8 string while looping) is very fast. Butforeach(a; someObject) {...}
, wheresomeObject
implementsopApply
, is a tad slower (because the loop body is wrapped into a delegate and opApply typically calls this delegate inside a loop, which generates some overhead). As usual, this won't matter to your code in 99.99% of the cases, asforeach
will always yield an (at least) decent implementation.
The main disadvantage (besides, occasionally, speed) is that some things cannot
be done with foreach
, namely many mutations of the thing being looped over
(e.g. resizing of an array within the loop body).
精彩评论