范围range是元素访问的抽象,范围强调如何访问容器元素,而不是如何实现容器。
Number ranges
数字范围是非常常用,这些数字范围是int类型的,下面是一些数字范围的示例-
//示例1 foreach (value; 3..7) //示例2 int[] slice=array[5..10];
Phobos Ranges
与结构和类接口有关的范围是phobos ranges, Phobos是D语言编译器随附的官方运行时和标准库。
有多种类型的范围,包括-
- InputRange
- ForwardRange
- BidirectionalRange
- RandomAccessRange
- OutputRange
InputRange
最简单的范围是输入范围,其他范围对它们所基于的范围提出了更高的要求,InputRange需要三个函数-
empty - 指定范围是否为空,当范围被认为是空时,返回true;否则为false。
front - 在范围的开头提供对元素的访问。
popFront - 通过删除第一个元素,从头开始缩短范围。
import std.stdio; import std.string; struct Student { string name; int number; string toString() const { return format("%s(%s)", name, number); } } struct School { Student[] students; } struct StudentRange { Student[] students; this(School school) { this.students=school.students; } @property bool empty() const { return students.length == 0; } @property ref Student front() { return students[0]; } void popFront() { students=students[1 .. $]; } } void main() { auto school=School([ Student("Raj", 1), Student("John", 2), Student("Ram", 3)]); auto range=StudentRange(school); writeln(range); writeln(school.students.length); writeln(range.front); range.popFront; writeln(range.empty); writeln(range); }
编译并执行上述代码后,将产生以下输出-
[Raj(1), John(2), Ram(3)] 3 Raj(1) false [John(2), Ram(3)]
ForwardRange
ForwardRange另外还需要InputRange的其他三个函数中的save函数,并在调用save函数时返回范围range的副本。
import std.array; import std.stdio; import std.string; import std.range; struct FibonacciSeries { int first=0; int second=1; enum empty=false; //无限范围 @property int front() const { return first; } void popFront() { int third=first + second; first=second; second=third; } @property FibonacciSeries save() const { return this; } } void report(T)(const dchar[] title, const ref T range) { writefln("%s: %s", title, range.take(5)); } void main() { auto range=FibonacciSeries(); report("Original range", range); range.popFrontN(2); report("After removing two elements", range); auto theCopy=range.save; report("The copy", theCopy); range.popFrontN(3); report("After removing three more elements", range); report("The copy", theCopy); }
编译并执行上述代码后,将产生以下输出-
Original range: [0, 1, 1, 2, 3] After removing two elements: [1, 2, 3, 5, 8] The copy: [1, 2, 3, 5, 8] After removing three more elements: [5, 8, 13, 21, 34] The copy: [1, 2, 3, 5, 8]
BidirectionalRange
除了ForwardRange函数外,BidirectionalRange还提供了两个函数,popBack函数类似于popFront函数,它从范围中删除最后一个元素。
import std.array; import std.stdio; import std.string; struct Reversed { int[] range; this(int[] range) { this.range=range; } @property bool empty() const { return range.empty; } @property int front() const { return range.back; //逆转 } @property int back() const { return range.front; //逆转 } void popFront() { range.popBack(); } void popBack() { range.popFront(); } } void main() { writeln(Reversed([ 1, 2, 3])); }
编译并执行上述代码后,将产生以下输出-
[3, 2, 1]
Infinite RandomAccessRange
与ForwardRange相比,还需要opIndex(),同样,在编译时将空函数的值称为false。
import std.array; import std.stdio; import std.string; import std.range; import std.algorithm; class SquaresRange { int first; this(int first=0) { this.first=first; } enum empty=false; @property int front() const { return opIndex(0); } void popFront() { ++first; } @property SquaresRange save() const { return new SquaresRange(first); } int opIndex(size_t index) const { /* 此功能以恒定时间运行 */ immutable integerValue=first + cast(int)index; return integerValue * integerValue; } } bool are_lastTwoDigitsSame(int value) { /* 必须至少有两位数字 */ if (value < 10) { return false; } /* 最后两位数字必须能被 11 整除 */ immutable lastTwoDigits=value % 100; return (lastTwoDigits % 11) == 0; } void main() { auto squares=new SquaresRange(); writeln(squares[5]); writeln(squares[10]); squares.popFrontN(5); writeln(squares[0]); writeln(squares.take(50).filter!are_lastTwoDigitsSame); }
编译并执行上述代码后,将产生以下输出-
25 100 25 [100, 144, 400, 900, 1444, 1600, 2500]
Finite RandomAccessRange
与Bidirectional range相比,还需要opIndex()和length。这将在使用斐波那契数列和先前使用的Squares Range示例进行解释。
import std.array; import std.stdio; import std.string; import std.range; import std.algorithm; struct FibonacciSeries { int first=0; int second=1; enum empty=false; //无限范围 @property int front() const { return first; } void popFront() { int third=first + second; first=second; second=third; } @property FibonacciSeries save() const { return this; } } void report(T)(const dchar[] title, const ref T range) { writefln("%40s: %s", title, range.take(5)); } class SquaresRange { int first; this(int first=0) { this.first=first; } enum empty=false; @property int front() const { return opIndex(0); } void popFront() { ++first; } @property SquaresRange save() const { return new SquaresRange(first); } int opIndex(size_t index) const { /* 此功能以恒定时间运行 */ immutable integerValue=first + cast(int)index; return integerValue * integerValue; } } bool are_lastTwoDigitsSame(int value) { /* 必须至少有两位数字 */ if (value < 10) { return false; } /* 最后两位数字必须能被 11 整除 */ immutable lastTwoDigits=value % 100; return (lastTwoDigits % 11) == 0; } struct Together { const(int)[][] slices; this(const(int)[][] slices ...) { this.slices=slices.dup; clearFront(); clearBack(); } private void clearFront() { while (!slices.empty && slices.front.empty) { slices.popFront(); } } private void clearBack() { while (!slices.empty && slices.back.empty) { slices.popBack(); } } @property bool empty() const { return slices.empty; } @property int front() const { return slices.front.front; } void popFront() { slices.front.popFront(); clearFront(); } @property Together save() const { return Together(slices.dup); } @property int back() const { return slices.back.back; } void popBack() { slices.back.popBack(); clearBack(); } @property size_t length() const { return reduce!((a, b) => a + b.length)(size_t.init, slices); } int opIndex(size_t index) const { /* 保存错误信息的索引 */ immutable originalIndex=index; foreach (slice; slices) { if (slice.length > index) { return slice[index]; } else { index -= slice.length; } } throw new Exception( format("Invalid index: %s (length: %s)", originalIndex, this.length)); } } void main() { auto range=Together(FibonacciSeries().take(10).array, [ 777, 888 ], (new SquaresRange()).take(5).array); writeln(range.save); }
编译并执行上述代码后,将产生以下输出-
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 777, 888, 0, 1, 4, 9, 16]
OutputRange
OutputRange表示流元素输出,类似于将字符发送到stdout,OutputRange需要支持put(range,element)操作,put()是在std.range模块中定义的函数。它在编译时确定范围和元素的函数,并使用最合适的方法来输出元素,一个简单的例子如下所示。
import std.algorithm; import std.stdio; struct MultiFile { string delimiter; File[] files; this(string delimiter, string[] fileNames ...) { this.delimiter=delimiter; /* 始终包含标准输出 */ this.files ~= stdout; /* 每个文件名的 File 对象 */ foreach (fileName; fileNames) { this.files ~= File(fileName, "w"); } } void put(T)(T element) { foreach (file; files) { file.write(element, delimiter); } } } void main() { auto output=MultiFile("\n", "output_0", "output_1"); copy([ 1, 2, 3], output); copy([ "learnfk", "toolfk", "chromefk" ], output); }
编译并执行上述代码后,将产生以下输出-
[1, 2, 3] ["learnfk", "toolfk", "chromefk"]
参考链接
https://www.learnfk.com/d-programming/d-programming-ranges.html
标签:std,教程,const,int,无涯,Ranges,range,return,first From: https://blog.51cto.com/u_14033984/8459614