Haxe ジェネリック関数 Generic functions を使ってみた
Haxe のジェネリック関数というものを利用してみました。利用してみたのは初めてに近いので、使用方法が誤っていたり もしくはもっと良い利用方法があるかもしれません。
まず以下の様な Polygon クラスがあるとします。
#if js import createjs.easeljs.Point; #else import flash.geom.Point; #end class Polygon { private var vertices:Array<Point>; public function new(){ vertices = [ new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10) ]; } }
Polygon クラス内には、頂点座標 Point クラスの配列 vertices があります。Point クラスは、AS3 あるいは CreateJS のクラスです。
ここで、物理演算ライブラリ Box2D や Nape から上記 Polygon.vertices の座標情報を利用したい場合、Point クラスを B2Vec2 クラス(Box2D)、あるいは Vec2 クラス(Nape)に変換する必要が出てきます。
まずは深く考えず、以下の様なメソッドを Polygon クラス内に設けるとします。
public function convertVerticesToB2Vec2():Array<B2Vec2>{ return [ for(vertex in vertices) new B2Vec2(vertex.x, vertex.y) ]; } public function convertVerticesToVec2():Array<Vec2>{ return [ for(vertex in vertices) new Vec2(vertex.x, vertex.y) ]; }
上記二つのメソッドの難点としましては、Polygon クラス内に Box2D と Nape の専用のクラスが記述されてしまっているという点にあります。例えば Box2D のみ利用したいのに Nape のクラスファイルもインポートしなくてはならない、という事態が発生してしまいます。
この問題を解決するために、convertVerticesToB2Vec2 と convertVerticesToVec2 は削除し、以下の様なメソッドに変更します。
public function convertVertices<T>(convertedClass:Class<T>):Array<T>{ return [ for(vertex in vertices) Type.createInstance(convertedClass, [vertex.x, vertex.y]) ]; }
これにより以下のように利用できます。
var polygon = new Polygon(); var vertices = polygon.convertVertices(B2Vec2); //Box2D //var vertices = polygon.convertVertices(Vec2); //Nape
Polygon クラスを利用する側で、Box2D あるいは Nape といったライブラリのインポートを選択できるようになります。
しかして上記 convertVertices メソッドは、Array や String クラスを指定する事もできてしまいます。Int を指定するとコンパイルエラーになります。
var polygon = new Polygon(); polygon.convertVertices(Array); //ok polygon.convertVertices(String); //ok polygon.convertVertices(Int); //error
本来は String クラスのコンストラクタ第二引数は指定できませんが、Type.createInstance 経由ですと指定可能となってしまうようです(第二引数は破棄されます)。
Type.createInstance 前にコンパイルエラーチェックはできないかと考えた所、以下の記述でいけました。
@:generic public function convertVertices<T:{function new(x:Float, y:Float):Void;}>(convertedClass:Class<T>):Array<T>{ return [ for(vertex in vertices) Type.createInstance(convertedClass, [vertex.x, vertex.y]) ]; }
これにより convertVertices には、「コンストラクタ引数に 二つの Float 型を指定するクラス」のみ指定が可能になります。(多分)
polygon.convertVertices(B2Vec2); //ok polygon.convertVertices(Vec2); //ok polygon.convertVertices(Array); //error polygon.convertVertices(String); //error
@:generic 指定に関しましては以下のサイトの Generic functions の項で説明がありますが、難しい英単語が多くてよくわかっていません。
参考)Haxe 3 New Features
http://haxe.org/manual/haxe3/features