11# Ranges
22
3- If a ` foreach ` is encountered by the compiler
3+ A range produces a series of elements (values) of the same type.
4+
5+ If a [ ` foreach ` statement] ( basics/foreach ) is encountered by the compiler
6+ with an expression recognised as a * range* :
47
58```
69foreach (element; range)
@@ -15,48 +18,81 @@ it's internally rewritten similar to the following:
1518for (auto __rangeCopy = range;
1619 !__rangeCopy.empty;
1720 __rangeCopy.popFront())
18- {
21+ {
1922 auto element = __rangeCopy.front;
2023 // Loop body...
2124}
2225```
2326
24- Any object which fulfills the following interface is called a ** range**
25- (or more specific ` InputRange ` ) and is thus a type that can be iterated over:
27+ The remainder of range behaviour is defined in the standard library.
28+
29+ ## Range Interface
30+
31+ Any object which has defined the following methods is called an * input range*
32+ and is thus a type that can be iterated over:
2633
2734```
28- interface InputRange(E)
35+ interface InputRange(E)
2936 {
3037 bool empty();
3138 E front();
3239 void popFront();
3340 }
3441```
3542
43+ ` E ` is the element type of the range.
44+
45+ A [ dynamic array] ( basics/arrays ) can be a range by importing ` std.range ` .
46+ This module defines range primitives on arrays, which can be called by
47+ [ UFCS] ( gems/uniform-function-call-syntax-ufcs ) :
48+
49+ ```
50+ import std.range;
51+
52+ int[] a = [1, 2, 3];
53+ assert(!a.empty);
54+ assert(a.front == 1);
55+ a.popFront();
56+ assert(a == [2, 3]);
57+ ```
58+
3659Have a look at the example on the right to inspect the implementation and usage
37- of an input range closer .
60+ of a custom input range.
3861
3962## Laziness
4063
4164Ranges are __ lazy__ . They won't be evaluated until requested.
42- Hence, a range from an infinite range can be taken:
65+ Hence, a range can produce infinite elements.
66+
67+ Below a range is created by calling ` repeat ` , which produces infinite
68+ elements, each the same as its initial argument. That range is
69+ processed by ` take ` , which will select the first N elements.
70+ Range functions are often called in a 'pipeline' style using
71+ [ UFCS] ( gems/uniform-function-call-syntax-ufcs ) chains:
4372
4473``` d
74+ import std.range;
75+
457642.repeat.take(3).writeln; // [42, 42, 42]
4677```
4778
4879## Value vs. Reference types
4980
50- If the range object is a value type, then range will be copied and only the copy
51- will be consumed:
81+ If the range object is a [ value type] ( basis/structs ) , then the range will be
82+ copied when passing it as a value parameter to a function, and only the copy
83+ will be consumed.
84+
85+ Below ` iota ` produces a struct value instance, and ` drop ` accepts it by value:
5286
5387``` d
88+ import std.range;
89+
5490auto r = 5.iota;
5591r.drop(5).writeln; // []
5692r.writeln; // [0, 1, 2, 3, 4]
5793```
5894
59- If the range object is a reference type (e.g. ` class ` or [ ` std.range.refRange ` ] ( https://dlang.org/phobos/std_range.html#refRange ) ),
95+ If the range object is a reference type (e.g. [ ` class ` ] ( basics/classes ) or [ ` std.range.refRange ` ] ( https://dlang.org/phobos/std_range.html#refRange ) ),
6096then the range will be consumed and won't be reset:
6197
6298``` d
0 commit comments