User defined type and foreach
Tony
tonytdominguez at aol.com
Sat Nov 18 05:24:30 UTC 2017
On Friday, 17 November 2017 at 17:55:30 UTC, Jonathan M Davis
wrote:
>
> When you have
>
> foreach(e; range)
>
> it gets lowered to something like
>
> for(auto r = range; !r.empty; r.popFront())
> {
> auto e = r.front;
> }
>
> So, the range is copied when you use it in a foreach. In the
> case of a class, it's just the reference that's copied. So,
> both "r" and "range" refer to the same object, but with a
> struct, you get two separate copies. So, when foreach iterates
> over "r", "range" isn't mutated.
Ah, I get it now ("r=range; process r"), thanks!
>
> So, in the general case, if you want to use a range in foreach
> without consuming the range, it needs to be a forward range,
> and you need to call save. e.g.
>
> foreach(e; range.save)
>
Seems like you can make class-based ranges to work on multiple
foreach calls without having to do save, although maybe it falls
apart in other usage. It also doesn't appear that the compiler
requires an @property annotation as specified in the interface :
import std.stdio : writeln;
class RefRange {
int foreach_index;
int[] items;
this(int[] src)
{
items = src;
}
bool empty()
{
if (foreach_index == items.length)
{
foreach_index = 0; // reset for another foreach
return true;
}
return false;
}
int front() { return items[foreach_index]; }
void popFront() { foreach_index++; }
}
void main() {
import std.stdio;
int[] ints = [1, 2, 3];
auto refRange = new RefRange(ints);
writeln("Ref 1st Run:");
foreach(i; refRange) writeln(i);
assert( ! refRange.empty);
writeln("Ref 2nd Run:");
foreach(i; refRange) writeln(i); // works
}
------------------------------------------
Ref 1st Run:
1
2
3
Ref 2nd Run:
1
2
3
More information about the Digitalmars-d-learn
mailing list