非类型类型参数
Non type type parameters
如果我有 类 只是代码中使用的一些常量不同怎么办?是否可以有一个没有运行时成本的通用实现?
这里是例子(有点长了...)
@:enum abstract Param(Int) {
var foo = 0;
var bar = 1;
}
class WorkBase {
public function new() {}
private inline function work_impl(p: Param): Void {
if(p == foo) {
trace('foo');
}
else {
trace('bar');
}
}
public function work(): Void {
}
}
class WorkFoo extends WorkBase{
override public function work(): Void {
work_impl(foo);
}
}
class WorkBar extends WorkBase {
override public function work(): Void {
work_impl(bar);
}
}
class Test {
public static function main() {
var workFoo = new WorkFoo();
var workBar = new WorkBar();
workFoo.work();
workBar.work();
}
}
使用 -D analyzer-optimize
编译后,我们将看到 WorkFoo.work()
和 WorkBar.work()
函数进行了优化,并且仅包含一个与 Param
值之一匹配的代码分支。现实生活中work_impl()
有很多这样的比较,都被优化掉了。不错。
但是如果我不想手动创建 WorkFoo
和 WorkBar
怎么办。是否可以这样做:
@:generic
class WorkBase<PARAM> {
private inline function work_impl(p: Param): Void {
...
}
public function work(): Void {
work_impl(PARAM);
}
}
我知道的最接近的是 const-type-parameter。但是我觉得通用构建在这里不是一个好的选择。
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
可以在没有 @:genericBuild
的情况下使用常量类型参数 - 与 @:generic
结合使用的常量类型参数足以获得所需的优化:
@:enum abstract Param(Int) from Int {
var foo = 0;
var bar = 1;
}
@:generic class Work<@:const PARAM:Int> {
public function new() {}
public function work():Void {
if (PARAM == foo) {
trace('foo');
} else {
trace('bar');
}
}
}
class Main {
public static function main() {
var workFoo = new Work<0>();
var workBar = new Work<1>();
workFoo.work();
workBar.work();
}
}
由于 @:generic
,每个常量值都会生成一个 class,例如在 JS 上输出如下所示:
var Work_[=11=] = function() {
};
Work_[=11=].prototype = {
work: function() {
console.log("source/Main.hx:11:","foo");
}
};
var Work_ = function() {
};
Work_.prototype = {
work: function() {
console.log("source/Main.hx:13:","bar");
}
};
请注意,由于某些原因,此示例在 Haxe 3.4.7 中失败并显示 "constraint check failure",但在 Haxe 4 预览版 4 及更高版本中运行良好。另一个限制是 new Work<Param.foo>()
和 new Work<foo>()
都不起作用 - 您需要传递实际的常量值。
如果我有 类 只是代码中使用的一些常量不同怎么办?是否可以有一个没有运行时成本的通用实现?
这里是例子(有点长了...)
@:enum abstract Param(Int) {
var foo = 0;
var bar = 1;
}
class WorkBase {
public function new() {}
private inline function work_impl(p: Param): Void {
if(p == foo) {
trace('foo');
}
else {
trace('bar');
}
}
public function work(): Void {
}
}
class WorkFoo extends WorkBase{
override public function work(): Void {
work_impl(foo);
}
}
class WorkBar extends WorkBase {
override public function work(): Void {
work_impl(bar);
}
}
class Test {
public static function main() {
var workFoo = new WorkFoo();
var workBar = new WorkBar();
workFoo.work();
workBar.work();
}
}
使用 -D analyzer-optimize
编译后,我们将看到 WorkFoo.work()
和 WorkBar.work()
函数进行了优化,并且仅包含一个与 Param
值之一匹配的代码分支。现实生活中work_impl()
有很多这样的比较,都被优化掉了。不错。
但是如果我不想手动创建 WorkFoo
和 WorkBar
怎么办。是否可以这样做:
@:generic
class WorkBase<PARAM> {
private inline function work_impl(p: Param): Void {
...
}
public function work(): Void {
work_impl(PARAM);
}
}
我知道的最接近的是 const-type-parameter。但是我觉得通用构建在这里不是一个好的选择。
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
可以在没有 @:genericBuild
的情况下使用常量类型参数 - 与 @:generic
结合使用的常量类型参数足以获得所需的优化:
@:enum abstract Param(Int) from Int {
var foo = 0;
var bar = 1;
}
@:generic class Work<@:const PARAM:Int> {
public function new() {}
public function work():Void {
if (PARAM == foo) {
trace('foo');
} else {
trace('bar');
}
}
}
class Main {
public static function main() {
var workFoo = new Work<0>();
var workBar = new Work<1>();
workFoo.work();
workBar.work();
}
}
由于 @:generic
,每个常量值都会生成一个 class,例如在 JS 上输出如下所示:
var Work_[=11=] = function() {
};
Work_[=11=].prototype = {
work: function() {
console.log("source/Main.hx:11:","foo");
}
};
var Work_ = function() {
};
Work_.prototype = {
work: function() {
console.log("source/Main.hx:13:","bar");
}
};
请注意,由于某些原因,此示例在 Haxe 3.4.7 中失败并显示 "constraint check failure",但在 Haxe 4 预览版 4 及更高版本中运行良好。另一个限制是 new Work<Param.foo>()
和 new Work<foo>()
都不起作用 - 您需要传递实际的常量值。