【问题标题】:Why do th array range primitives consume their sources?为什么数组范围原语会消耗它们的源?
【发布时间】:2015-08-24 08:13:43
【问题描述】:

专用于内置数组的范围原语消耗它们的源,但人们可以轻松地设计一个范围系统,该系统宁愿基于源的.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");
}

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

这种设计有什么理由吗?

【问题讨论】:

  • 你的代码和 stdlib 的东西应该编译成完全正确的代码......编写高效代码的重要提示:不要假设事情,实际检查编译器和库的作用!

标签: range d pointer-arithmetic


【解决方案1】:

我同意你的观点,没有理由在每个 popFront 重新分配。好在那时没有发生这种情况!

popFront 机制和你介绍的很像,source 没有被消耗,只有你调用popFront 的数组(因为它毕竟是一个pop) .您实现的是对数组进行切片时发生的情况:您获得原始数组的引用范围:

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 可能看起来不是很有用,因为我们将它与数组一起使用,但在处理“纯”范围时它非常重要,因为范围通常懒惰不使用它。由于使用的是范围的副本而不是初始范围的副本,因此我们可以安全地将此副本传递给函数,并且仍然保持初始惰性范围不变。

【讨论】:

    猜你喜欢
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 1970-01-01
    • 2019-05-18
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多