What is a “yield return” equivalent in the D programming language?

前端 未结 3 674
小鲜肉
小鲜肉 2021-02-01 17:11

Here is a simple generator in C#.

    IEnumerable Foo()
    {
        int a = 1, b = 1;
        while(true)
        {
            yield return b;
             


        
相关标签:
3条回答
  • 2021-02-01 17:33

    See here; example excerpt below:

    module main;
    
    import std.stdio;
    import generators;
    
    void genSquares(out int result, int from, int to)
    {
        foreach (x; from .. to + 1)
            yield!result(x * x);
    }
    
    void main(string[] argv)
    {
        foreach (sqr; generator(&genSquares, 10, 20))
            writeln(sqr);
    }
    
    0 讨论(0)
  • 2021-02-01 17:39

    There's no exact equivalent in D. Here are some rough equivalents:

    Using opApply-style internal iteration. This doesn't allow iterating over two iterators in lockstep, though:

    struct Foo {
        int opApply(int delegate(ref int) dg) {
            int a = 1, b = 1;
            int result;
            while(true) {
                result = dg(b);
                if(result) break;
                int temp = a + b;
                a = b;
                b = temp;
            }
    
            return result;
        }
    }
    
    void main() {
        // Show usage:
        Foo foo;
        foreach(elem; foo) {
            // Do stuff.
        }
    }
    

    Use ranges. These are slightly harder to write in some cases, but are very efficient and allow lockstep iteration. This can also be iterated over with a foreach loop, exactly like the opApply version:

    struct Foo {
        int a = 1, b = 1;
    
        int front() @property {
            return b;
        }
    
        void popFront() {
            int temp = a + b;
            a = b;
            b = temp;
        }
    
        // This range is infinite, i.e. never empty.
        enum bool empty = false;
    
        typeof(this) save() @property { return this; }
    }
    

    If you really need coroutine-style stuff you can combine ranges and opApply together using core.thread.Fiber, but you'll probably find that either ranges or opApply does what you need almost all the time.

    0 讨论(0)
  • 2021-02-01 17:54

    The std.concurrency module now has a Generator class which makes this even easier (and you don't need a third-party library).

    The class is an input range, so it can be used with for loops and all the standard std.range/std.algorithm functions.

    import std.stdio;
    import std.range;
    import std.algorithm;
    import std.concurrency : Generator, yield;
    
    void main(string[] args) {
        auto gen = new Generator!int({
            foreach(i; 1..10)
                yield(i);
        });
    
        gen
            .map!(x => x*2)
            .each!writeln
        ;
    }
    
    0 讨论(0)
提交回复
热议问题