我有一个看起来像这样的结构:
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
答案 0 :(得分:8)
使用tupleof
:
foreach (ref part; msg.tupleof)
sendPart(part);
这将使用sendPart
,mime
和data
(结构的字段,按照声明的顺序)调用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
函数,例如map
,array
,joiner
等等
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;
}