tin*_*lyx 3 generics haxe generic-programming
我试图在Haxe3中为模板类型A编写一个通用比较函数(如c strcmp),假设此模板类型具有小于或等于运算符"<=".
我在Haxe3文档(http://haxe.org/manual/haxe3/features)中看到,如果您想假设模板类型具有新功能,您可以执行类似的工作:
@:generic static function foo<T:{function new(s:String):Void;}>(t:T) {
trace(Type.typeof(t)); // TClass([class String]) / TClass([class Template])
return new T("foo");
}
Run Code Online (Sandbox Code Playgroud)
所以,我用"le"函数尝试了相同的技术:
class Main {
@:generic static public function compare_<A:{function le(y:A):Bool;}>(x:A,y:A): Int {
if (x.le(y) && y.le(x)) return 0;
else if (x.le(y)) return -1;
else return 1;
}
static function main() {
var a:MyInt = new MyInt(1);
var b:MyInt = new MyInt(2);
trace(compare_(a,b));
}
}
class MyInt {
var data:Int;
public function new(i:Int) {this.data = i; }
public function le(y:MyInt){return data <= y.data;}
}
Run Code Online (Sandbox Code Playgroud)
上面的compare_函数适用于具有先决条件"le"功能的任何类型.上面的代码按预期返回-1.但显然,为Int创建一个新类是非常不方便的,只是为了提供这个le功能.我的问题是,有没有办法重新编写compare_函数,使其适用于任何模板类型(Int,Float,其他具有重载运算符的类型),并定义了"<="运算符?
以下是我的尝试:
@:generic static public function compare_<A:{@:op(X <= Y) function le(x:A,y:A):Bool;}>(x:A,y:A): Int {
if (x <= y && y <= x) return 0;
else if (x <= y) return -1;
else return 1;
}
Run Code Online (Sandbox Code Playgroud)
这当然不编译.Haxe抱怨"le"未定义.
我正在寻找不涉及宏的轻量级解决方案,因为我打算在不依赖Boot的情况下在其他语言中重用haxe生成的代码.或者scuts.动态对我的目的也不利,因为根本没有类型安全.
提前致谢.
更新:我做了一些额外的阅读,并认为我可能能够le使用using和callback机制将方法注入我想要的每种类型.请参阅我的相关问题,"导入和使用可能不会在类型声明后出现" - 使用魔法的haxe.
处理问题的两种安全方式:
class Main {
macro static public function compare_(a, b)
return macro @:pos(a.pos) {
var a = $a,
b = $b;
if (a <= b)
if (b <= a) 0;
else -1;
else 1;
}
static function main() {
var a = 1,
b = 2;
trace(compare_(a,b));
}
}
Run Code Online (Sandbox Code Playgroud)
abstract Comparator<T>({f: T->Int }) {
public function new(f)
this = { f: f };
public function compare(other:T):Int
return this.f(other);
@:from static function fromInt(i:Int)
return simple(i);
@:from static function fromFloat(f:Float)
return simple(f);
@:from static function fromString(s:String)
return simple(s);
@:from static function fromComparable<A>(o:{ function compareTo(other:A):Int; })
return new Comparator(o.compareTo);
static function simple<X>(o:X):Comparator<X>
return new Comparator(Reflect.compare.bind(o));
}
class Main {
static public function compare_<A>(a:Comparable<A>, b:A)
return a.compare(b);
static function main() {
function comparable(value)
return {
value: value,
compareTo: function(other)
return Reflect.compare(value, other.value)
}
trace(compare_(1,2));
trace(compare_(1.5,2.5));
trace(compare_('foo','bar'));
trace(compare_(comparable(1),comparable(2)));
}
}
Run Code Online (Sandbox Code Playgroud)