LoginSignup
11

More than 5 years have passed since last update.

コルーチンを for で使い回したときの各言語における振る舞い

Last updated at Posted at 2015-12-13

言語によって振る舞いが異なるようなのでメモ。

C#

using System;
using System.Collections.Generic;

class Program {
    static IEnumerable<string> Three() {
        yield return "one";
        yield return "two";
        yield return "three";
    }

    static void Main() {
        var co = Three();

        Console.WriteLine("1");
        foreach (var x in co)
            Console.WriteLine(x);

        Console.WriteLine("2");
        foreach (var x in co)
            Console.WriteLine(x);
    }
}

実行結果:

1
one
two
three
2
one
two
three

JavaScript(Node)

"use strict"

function* three() {
    yield "one";
    yield "two";
    yield "three";
}

function main() {
    var co = three();

    console.log("1");
    for (let x of co)
        console.log(x);

    console.log("2");
    for (let x of co)
        console.log(x);
}

main();

実行結果:

1
one
two
three
2

Julia

function three()
    produce("one")
    produce("two")
    produce("three")
end

function main()
    co = @task three()

    println("1")
    for x = co
        println(x)
    end

    println("2")
    for x = co
        println(x)
    end
end

main()

実行結果:

1
one
two
three
2

Lua

function three()
    coroutine.yield("one")
    coroutine.yield("two")
    coroutine.yield("three")
end

function main()
    co = coroutine.wrap(three)

    print("1")
    for x in co do
        print(x)
    end

    print("2")
    for x in co do
        print(x)
    end
end

main()

実行結果:

1
one
two
three
2
lua: a.lua:17: cannot resume dead coroutine
stack traceback:
    [C]: in function 'for iterator'
    a.lua:17: in function 'main'
    a.lua:23: in main chunk
    [C]: in ?

Python

def three():
    yield "one"
    yield "two"
    yield "three"

def main():
    co = three()

    print("1")
    for x in co:
        print(x)

    print("2")
    for x in co:
        print(x)

main()

実行結果:

1
one
two
three
2

追記:

下記のような方法もあります。

class three:
    def __iter__(self):
        yield "one"
        yield "two"
        yield "three"

実行結果:

1
one
two
three
2
one
two
three

Ruby

def three
  Enumerator.new do |y|
    y << "one"
    y << "two"
    y << "three"
  end
end

def main
  co = three()

  puts "1"
  for x in co
    puts x
  end

  puts "2"
  for x in co
    puts x
  end
end

main

実行結果

1
one
two
three
2
one
two
three

まとめ

C# と Ruby では、for 文で同じコルーチンを使い回すと要素の先頭から取り出されるような振る舞いとなった。JavaScript(Node), Julia, Lua, Python では、コルーチンは使い切りで使い回しができないような振る舞いとなった。

各言語のバージョン

  • C#: Mono JIT compiler version 4.2.1
  • Node v5.1.0
  • julia version 0.4.0
  • Lua 5.3.0
  • Python 3.4.0 (v3.4.0:04f714765c13, Mar 15 2014, 23:02:41)
  • ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14]

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11