2015-11-30 15 views
6

Ben şuna benzer bir yapı vardır:Bıkmadan

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

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

ve ben istiyorum böyle bir şey ile başka bir sınıfta, üzerinde yineleme için:

struct Socket { 
    ... 

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

    ... 
} 

bu mu mümkün? Python'un __iter__'a MultipartMessage'da benzer bir şeyi kullanmak istiyorum, bu da alanları belirli bir sırayla iade edebilir ve ideal olarak header.serialize() gibi bazı ek kodları çalıştırabilir.

ubyte[] __iter__() { 
    yield mime; 
    yield data; 
    yield header.serialize(); //header.serialize returns a ubyte[] 
} 
+0

(http://dlang.org/spec/statement.html#ForeachStatement) için birçok yol vardır foreach ifadeleri ile anlaşma. En kolayı belki de giriş aralığıdır, ancak her bir yinelemenin neyi istediğinizi net olarak görmeden, sizin için en iyi yolun hangisi olduğunu söylemek zordur. Daha hassas olabilir misin? – cym13

cevap

2

İstediğiniz en yakın şey muhtemelen opApply.

Foreach over Structs and Classes wit opApply

Bu çalışacaktır http://dlang.org/spec/statement.html Bölüm bakınız: belgelerinde belirtildiği gibi

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; 
} 
8

Kullanım tupleof:

İdeal bu (pseudocode) gibi bir şey olacağını MultipartMessage bir fonksiyon eklersiniz

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

Bu arayacak sendPart ile mime, data ve header (yapının alanları, bildirildikleri sırayla). Alanlarını, ör. static if (!is(typeof(part) == Header)).

sen __traits(identifier) kullanabilirsiniz, alanın adını almak için:

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

(__traits(identifier, part)part dönecekti.)

da yöntemler döndüren __traits(allMembers) da var.

+0

'tupleof', Python'un' __iter__' için iyi bir analog değildir. –

+0

Belki bu soruyu yanlış anladım, ancak D'nin __ter__'si “opApply”. –

+0

D ''__iter__'' opApply' ile ne demek istiyorsunuz? Bir yapı üzerinde yinelemek için nasıl kullanılabilir? –

2

birkaç

One


D.

nesnelerin üzerinde iterate yapmak yolları InputRange API uygulamaktır vardır. Giriş aralıkları yineleyicilere benzer, ancak farklı bir API'ye sahip. Arabirim arabirimi uygulamak, map, array, ve benzeri gibi nesnenizdeki tüm std.range/ std.algorithm işlevlerini kullanabileceğiniz anlamına gelir.

D, rastgele koleksiyonlardan bir iterator almak için __iter__ işlevine sahip değildir, bu nedenle bir giriş aralığı döndüren bir işlevi uygulamanız gerekir.

import std.range; 

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

Bu header.serialize sonra, data bayt ardından mime bayt, aşağıdakilerden oluşan, bir ubyte giriş aralığı döndürür.


Ayrıca yapı üzerinde opApply yöntemi uygulayabilir. opApply yalnızca foreach ile çalışır, böylece aralık yöntemlerini bununla kullanamazsınız, ancak döngü iş parçacığını yürütmek gibi işleri ayrı iş parçacıklarında yapmanızı sağlar.

opApply'un özü, D'nin döngü gövdesini bir işlev olarak opApply'a geçirmesidir; Yani, foreach(x; myObj) { body }, myObj.opApply((x) { body })'a dönüştürülür.

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

Ancak bunun yerine bu seçeneklerden birinin, sana bir çıkış aralığı alır ve ona veri yazar senin nesne üzerinde bir işlevi uygulamak öneririz.

Çıkış aralığı, diğer nesneleri kabul eden ve onlara bir şey yapan bir nesnedir. Bu durumda çıkış aralığı, bir çıkış akışına benzer şekilde ubyte s kabul etmelidir. Bir dizinin dönüştürülebilir bir Appender içine çıkışını saklar

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 
} 

Örnek kullanım,: anlamına gelir o zaman soket üstünde bir çıkış aralığını uygularsanız

import std.array; 

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

, çıktı aralığı çözümü , yığından herhangi bir belleği ayırmak zorunda değildir.


Kontrol dışarı Programming in D kitabı (özellikle Aralıkları ve Daha Aralıkları bölümler) Kendi aralıkları nasıl uygulanacağı konusunda bilgi için.