非类型类型参数

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()有很多这样的比较,都被优化掉了。不错。

但是如果我不想手动创建 WorkFooWorkBar 怎么办。是否可以这样做:

@: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>() 都不起作用 - 您需要传递实际的常量值。