迭代dlang结构

时间:2015-11-30 23:05:12

标签: iteration d

我有一个看起来像这样的结构:

struct MultipartMessage {
    ubyte[] mime, data;
    Header header;

    void setSender(string sender) {
        header.sender = sender;
    }
    void setId(int id) {
        header.id = id;
    }
}

我想迭代它,在另一个类中使用类似的东西:

struct Socket {
    ...

    void send(MultipartMessage msg) {
        foreach (part; msg) {
            sendPart(part);
        }
    }

    ...
}

这可能吗?我想在__iter__中使用类似于Python MultipartMessage的内容,可以按特定顺序返回字段,理想情况下甚至可以运行一些其他代码,例如{{1} }}

理想情况下,我会向header.serialize()添加一个看起来像这样的函数(伪代码):

MultipartMessage

3 个答案:

答案 0 :(得分:8)

使用tupleof

foreach (ref part; msg.tupleof)
    sendPart(part);

这将使用sendPartmimedata(结构的字段,按照声明的顺序)调用header。您可以通过检查字段类型来过滤字段。 static if (!is(typeof(part) == Header))

要获取字段的名称,您可以使用__traits(identifier)

foreach (i, ref part; msg.tupleof)
    writeln(__traits(identifier, msg.tupleof[i]));

__traits(identifier, part)将返回part。)

还有__traits(allMembers),它也会返回方法。

答案 1 :(得分:2)

有几种方法可以在D中迭代对象。

一个是实现 InputRange API。输入范围与迭代器类似,但具有不同的API。实现范围界面意味着您可以使用对象上的所有std.range / std.algorithm函数,例如maparrayjoiner等等

D没有__iter__函数从任意集合中获取迭代器,因此您需要实现一个返回输入范围的函数。

import std.range;

auto bytes() {
    return chain(mime, data, header.serialize);
}

这将返回ubyte输入范围,包括mime中的字节,后跟data中的字节,然后是header.serialize中的字节。

您还可以在结构上实现opApply方法。 opApply仅适用于foreach,因此您无法使用范围方法,但它允许您执行诸如在单独的线程中执行循环体的操作。

opApply的要点是D将循环体传递给opApply作为函数;也就是说,foreach(x; myObj) { body }会转换为myObj.opApply((x) { body })

void opApply(void delegate(ubyte[] part) loopbody) {
    loopbody(mime);
    loopbody(data);
    loopbody(header.serialize());
}

但是,我建议您在对象上实现一个带有输出范围并将数据写入其中的函数,而不是其中任何一个选项。

输出范围是接受其他对象的对象,并对它们执行某些操作。在这种情况下,输出范围应该接受ubyte s,使其类似于输出流。

void serialize(Range)(ref Range outRange) if(isOutputRange!(Range, ubyte)) {
    put(outRange, mime); -- `put` simply feeds data into the output range
    put(outRange, data);
    header.serialize(outRange); // No longer have to allocate/return a ubyte array
}

示例用法,将输出存储到Appender,可以将其转换为数组:

import std.array;

auto serializedDataAppender = appender!ubyte();
myMsg.serialize(serializedDataAppender);
auto serializedData = serializedDataAppender.data;

如果在套接字顶部实现输出范围,那么这意味着输出范围解决方案不必从堆分配任何内存。

查看Programming in D本书(特别是范围更多范围部分),了解有关如何实施自己的范围的信息。

答案 2 :(得分:2)

最接近你想要的东西可能是opApply

请参阅http://dlang.org/spec/statement.html,第Foreach over Structs and Classes wit opApply部分

这将有效:

int opApply(int delegate(ref ubyte[]) dg) {
    int result = 0;
    result = dg(mime);
    result = dg(data);
    ubyte[] header_bytes = header.serialize();
    result = dg(header_bytes);
    return result;
}