IEnumerable(オブジェクトをforeachできるようにする)
プログラミングC# p207
さっきのRectangleをEnumerableにしてみる。
順番にxとyを返すというもの。
using System; using System.Collections; using System.Collections.Generic; class Rectangle : IEnumerable { private int x; private int y; public Rectangle(int x, int y) { this.x = x; this.y = y; } public IEnumerator GetEnumerator() { yield return x; yield return y; } static void Main(string[] args) { Rectangle r = new Rectangle(4, 5); foreach(int i in r) { Console.WriteLine("i = {0}", i); } } }
結果はこう。
i = 4 i = 5
「using System.Collections;」を抜かすとこんなエラーが出る。
IEnumerableTest.cs(5,19): error CS0305: ジェネリック 型 'System.Collections.Generic.IEnumerable' の使用には、'1' 型の引数が必要です。 c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll: (以前のエラーに関連するシンボルの位置) IEnumerableTest.cs(16,9): error CS0305: ジェネリック 型 'System.Collections.Generic.IEnumerator ' の使用には、'1' 型の引数が必要です。 c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll: (以前のエラーに関連するシンボルの位置)
ちょっとはまった。。
ちなみにRuby。
class Rectangle def initialize(x, y) @x = x; @y = y; end def each() yield @x; yield @y; end end r = Rectangle.new(4, 5) r.each { |i| print "i = #{i}\n" }
結果はこう。
i = 4 i = 5
Enumerableをincludeすると、さらに色々できるようになるらしい。
そういやJava。Enumerableというか、拡張for文で使うことの出来るオブジェクトの要件ってなんなんだろう?
Javaのドキュメントからたどり、JSR201を経由して、Java Language Specification Third Editionにたどり着きました。
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.14.2
これによると、
The Expression must either have type Iterable or else it must be of an array type (§10.1), or a compile-time error occurs.
で、java.lang.Iterableを実装するか配列であればOKらしい。
早速Rectangle.javaを実装してみる。
import java.util.*; public class Rectangle implements Iterable { private int x; private int y; public Rectangle(int x, int y) { this.x = x; this.y = y; } public Iterator iterator() { return new Iterator() { private int count = 0; public boolean hasNext() { if(count < 2) { return true; } else { return false; } } public Object next() { switch(count) { case 0: count++; return new Integer(x); case 1: count++; return new Integer(y); default: return null; } } public void remove() { } }; } public static void main(String[] args) { Rectangle r = new Rectangle(4, 5); for(Object o : r) { System.out.println(o); } } }
う〜ん。ちょっと手軽さに欠けますね。
使うほうは簡単だが、作る方は手間がかかると。
ちなみに結果はこう。
4 5