如何在D语言中使一个对象(类)可被foreach循环?

7

如何使一个类在foreach语句中可用?

该类包含一个关联数组(例如string[string])。因此,foreach语句使用此数组作为源。

所以这就是我想要的:

auto obj = new Obj();
foreach (key, value; obj)
{
    ...
}

我需要实现类似这样的接口吗?

编辑:

解决方案:

public int opApply(int delegate(ref string, ref Type) dg)
{
    int result = 0;

    foreach (ref key, ref value; data)
    {
        result = dg(key, value);
        if (result != 0)
        {
            break;
        }
    }

    return result;
}

同样的操作也适用于public int opApply(int delegate(ref Type) dg)。

2个回答

4

D1:

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

D2

使用范围可以迭代结构体和类对象,这意味着必须定义一组属性:


2
我认为基于范围的foreach尚不支持解包。而且opApply在D2中也可以使用。 - kennytm
opApply是解决方案,谢谢! - VDVLeon

3
OP发布的解决方案是有效的,但在D2中有另一种具有不同权衡的解决方案。在D中,迭代可以分为内部迭代和外部迭代,其中内部迭代由opApply处理,外部迭代由范围处理。
内部迭代使被迭代对象控制调用堆栈。例如,被迭代对象可以使用递归而不维护显式堆栈,但无法同时迭代多个结构。相反,外部迭代则实现了这一点。
通过范围实现外部迭代。范围是定义了三个方法的任何类或结构:front()提供对范围中第一个元素的访问,popFront()推进范围,empty()返回true如果范围为空,则如果范围是无限的,则可以将空声明为常量而不是成员函数。通过这种方式,调用者可以控制调用堆栈,这是一种根据情况好坏参差不齐的权衡。
以下是使用范围进行迭代的示例:
/**This struct lazily produces all Fibonacci numbers.*/
struct Fibonacci {
    ulong num1 = 0;
    ulong num2 = 1;

    ulong front() {
        return num1 + num2;
    }

    void popFront() {
        auto newNum2 = num1 + num2;
        num1 = num2;
        num2 = newNum2;
    }

    // A range of Fibonacci numbers is infinite.
    enum bool empty = false; 
}

那么,关于foreach(key,value;collection)是否有关于Range原语的编译器重写呢?我还没有看到相关信息,但我很希望有这样的东西:D - Tim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接