Почему примитивы диапазона массива потребляют свои источники?
Примитивы диапазона, которые предназначены для встроенных массивов, потребляют свои источники, но можно легко спроектировать систему диапазона, которая скорее будет основана на .ptr
источника (на первый взгляд это более гибко).
struct ArrayRange(T)
{
private T* _front;
private T* _back;
this(ref T[] stuff) {
_front = stuff.ptr;
_back = _front + stuff.length;
}
@property bool empty(){return _front == _back;}
@property T front(){ return *_front;}
@property T back(){return *_back;}
void popFront(){ ++_front;}
void popBack(){--_back;}
T[] array(){return _front[0 .. _back - _front];}
typeof(this) save() {
auto r = this.array.dup;
return typeof(this)(r);
}
}
void main(string[] args)
{
auto s = "bla".dup;
// here the source is 'fire-proofed'
auto rng = ArrayRange!char(s);
rng.popFront;
assert (s == "bla");
assert (rng.array == "la");
// default primitives: now the source is consumed
import std.array;
s.popFront;
assert (s == "la");
}
Почему система по умолчанию не основана на арифметике указателей, так как всплывающее окно означает перераспределение / меньшую эффективность?
Есть ли обоснование для этого дизайна?
1 ответ
Я согласен с вами, нет причин для перераспределения на каждом popFront
, Хорошо, что это не то, что происходит тогда!
popFront
механизм очень похож на то, что вы представили, и источник не потребляется, только массив, на котором вы вызываете popFront
(потому что это поп-музыка в конце концов). То, что вы реализовали, это то, что происходит, когда вы разрезаете массив: вы получаете диапазон ссылок на исходный массив:
auto a = [1, 2, 3];
auto s = a[];
s.popFront;
assert(s == [2, 3]);
assert(a == [1, 2, 3]);
.dup
существует возможность предоставить копию массива, чтобы вы могли безопасно изменять копию, не изменяя оригинал, поэтому он копирует исходный массив, а затем предоставляет диапазон ввода для этой копии. Конечно, вы можете изменить копию (в этом все дело), и popFront
изменит это, но все еще использует арифметику указателя и без изменения источника.
auto a = [1, 2, 3];
auto s = a.dup;
s.popFront;
assert(s = [2, 3]);
assert(a = [1, 2, 3]);
.dup
может показаться не очень полезным как таковым, потому что мы используем его с массивами, но это действительно важно при работе с "чистыми" диапазонами, так как диапазон часто ленив, чтобы не использовать его. Так как копия диапазона используется, а не исходная, мы можем безопасно передать эту копию функции и при этом сохранить наш начальный ленивый диапазон без изменений.