为什么数组范围原语消耗它们的来源?

Abs*_*ype 4 d range pointer-arithmetic

专用于内置阵列的范围原语消耗它们的源,但是可以很容易地设计一个范围系统,而不是基于.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");
}
Run Code Online (Sandbox Code Playgroud)

为什么默认系统不是基于指针算法,因为弹出前面意味着重新分配/效率较低?

这个设计有什么理由吗?

cym*_*m13 5

我同意你的观点,没有理由重新分配popFront.好的事情不是那么发生的事情!

popFront你所呈现的机制非常相似,并且没有消耗,只有你调用的数组popFront(因为它毕竟是一个pop).您实现的是切片数组时发生的情况:您获得原始数组的参考范围:

auto a = [1, 2, 3]; 
auto s = a[];
s.popFront;
assert(s == [2, 3]);
assert(a == [1, 2, 3]);
Run Code Online (Sandbox Code Playgroud)

.dup是否提供数组的副本,以便您可以安全地修改副本而不更改原始数据,因此它复制原始数组,然后为此副本提供输入范围.当然你可以修改副本(这就是要点),并且popFront会改变它但仍然使用指针算法而不改变源.

auto a = [1, 2, 3];
auto s = a.dup;
s.popFront;
assert(s = [2, 3]);
assert(a = [1, 2, 3]);
Run Code Online (Sandbox Code Playgroud)

.dup因为我们在数组中使用它可能看起来不太有用,但在处理"纯"范围时它非常重要,因为范围通常很懒,不能消耗它.由于范围的副本被消耗而不是初始副本,我们可以安全地将此副本传递给函数,并且仍然保持最初的惰性范围.