d的opnext
原文
我发现empty/front/popNext协议在一般(至少在Weka代码库中)非常麻烦,人们更喜欢opApply(尽管有自己的问题).
今天甚至遇见了使用现有协议无法解决问题:如果foreach中断了,消费区间(比如文件流)不应消费.使用opApply,这很容易(闭包返回非零值),但是使用popNext,这很难.我不详细讨论细节,所以直接跳到建议的协议.
bool opNext(out T elem) {...}
如果"产生"了一个元素,下个(opNext)操作,则返回true,如果到达了结尾,则返回false.
foreach (elem; range) {
...
}
只是降级到
T elem;
while (range.opNext(elem)) {
...
}
当然,该协议可与现有协议并存,只是在降级规则中优先.具体示例:
struct LinkedList {
int value;
LinkedList* next;
struct Range {
LinkedList* cursor;
bool opNext(out int val) nothrow @nogc {
if (cursor is null) {
return false;
}
val = cursor.value;
return true;
}
}
auto members() {return Range(&this);}
}
foreach (val; myList.members) {
...
}
注意:
0,对新协议也可用保存()/save(),它只需要复制迭代器的状态.
1,也许加上opPrev来搞定双向区间是可行的,但,用途不大.
2,在新协议中更容易链接map/filter/etc
出于好奇:你认为,对比如下,其优缺点:
Option!(T) opNext() { ... }
选项(Option)是选项类型实现,因此包含了是否产生元素问题.这是简化/重新设计区间概念的另一个建议.)
基于选项设计的优点是不需要持久的前(front),更适合(如,从流中读的)真输入区间.
对前方法有可引用的持久底层数据,这可能更加笨拙.
mixin template NextToRange(ElementType) {
ElementType _value;
bool _haveValue;
@property {
bool empty() {
return !_haveValue;
}
ElementType front() {
assert(_haveValue);
return _value;
}
}
void popFront() {
_haveValue = nextValue(_value);
}
}
不需要破坏很大比例标准库就可使用它;).
浙公网安备 33010602011771号