перегрузка оператора foreach в языке программирования d - PullRequest
7 голосов
/ 01 февраля 2012

Здравствуйте. Я хотел бы определить свою собственную коллекцию классов и сделать ее итеративной в выражении foreach, например:

public class Collection(Type)
{
    ...
    private T head;
    private Collection!(T) queue;
}

Collection!(int) temp;
foreach (int t; temp) { ... }

Какие методы я должен определить и как?

Ответы [ 3 ]

9 голосов
/ 01 февраля 2012

вы можете указать функции front, popfront() и empty: (но это будет использовать вашу коллекцию, если вы не используете save ())

public class Collection(T) { ... private T head;  private Collection!(T) queue;

    @property T front(){
        return head;
    }

    @property bool empty(){
        return queue is null;
    }

    void popfront(){
        head = queue.head;
        queue = queue.queue;
    }

    Collection!T save(){
        return new Collection!T(head,queue);
    }

}

или используйте выделенную структуру для итерации (как это делается в модуле std.container

public class Collection(T) { ... private T head;  private Collection!(T) queue;

    Range opSlice(){
        return Range(head,queue);
    }

    struct Range{
        T h;
        Collection!(T) q;
        this(T he, Collection!(T) qu){
            h=he;
            q=qu;
        }
        @property T front(){
            return h;
        }

        @property bool empty(){
            return q is null;
        }

        void popfront(){
            h = q.head;
            q= q.queue;
        }

        Collection!T save(){
            return this;
        }


    }
}

так итерация выполняется так

Collection!(int) temp; foreach (int t;temp[]) { ... }

Вы также можете добавить opApply для обычного foreach:

public int opApply(int delegate(ref T) dg){
    int res=0;
    foreach(ref T;this[]){
        res = dg(t);
        if(res)return res;
    }
    return res;
}
5 голосов
/ 01 февраля 2012

Взгляните на эту документацию по ForeachStatements и прокрутите немного вниз.

Если я правильно читаю ваш пример, вы можете определить opApply для Collection следующим образом:

public int opApply(int delegate(ref T) dg){

    Collection!T p = this;

    int res = 0;
    while(!res && p !is null){
        res = dg(p.head);
        p = p.queue;
    }

    return res;
}
3 голосов
/ 01 февраля 2012

Ваш класс Collection должен реализовывать opApply. Ваше тело foreach становится делегатом внутреннего цикла for, и вы перебираете свою внутреннюю коллекцию (в вашем случае очередь), используя цикл for.

Рассмотрим пример, приведенный в документации

class Foo {
    uint array[2];

    int opApply(int delegate(ref uint) dg)    
    { int result = 0;

        for (int i = 0; i < array.length; i++)
        {
            result = dg(array[i]);
            if (result)
                break;
        }
        return result;
    }
}
...