使用HAXE宏来实例化一个带参数的类

问题描述 投票:6回答:2

我试图做一些黑暗魔法与HAXE宏,我有一个类名为Entity,我想添加一个池与staticprivate修饰符:

Pool.hx

package exp;

class Pool<T> {
    public function new(clazz:Class<T>) {

    }
}

Entity.hx

package exp;

@:build(exp.PoolBuilder.build())
class Entity {
    public function new(){}
}

PoolBuilder.hx

package exp;

import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;

class PoolBuilder {
    static public macro function build() : Array<Field> {
        var fields = Context.getBuildFields();
        var clazz = Context.getLocalClass();

        var typePath = { name:"Pool", pack:["exp"], params: [TPType(TPath({name: "Entity", pack: ["exp"]}))] }
        var pool = macro new $typePath(/* clazz? */);
        fields.push({
            name: "_pool",
            access: [APrivate, AStatic],
            pos: Context.currentPos(),
            kind: FVar(macro: exp.Pool, pool)
        });

        return fields;
    }
}

我有一个问题与typePath参数,可以和传递Class<T>作为参数传递给构造函数。编译器显示此错误:

EXP / Entity.hx:3:字符1-7:类型参数为exp.Pool无效数

EXP / Entity.hx:4:线4-6:定义在这个类

有谁知道如何解决这个问题?

macros haxe
2个回答
5
投票

建筑领域人工就像是有点乏味 - 我建议使用class reification相反,在这里你可以表达领域定期HAXE代码:

macro class {
    static var _pool = new Pool(/* clazz */);
}

这绕过了问题“的类型参数无效的数字”完全是 - 只是让类型推断的伎俩,并省略new Pool()类型参数。

为构造函数调用的参数当然是可变的,所以我们还是需要使用一些expression reificationexp.Entity是现场表达,所以我们必须使用$p{}。我们可以构造结合clazz.packclazz.name需要它的类路径:

class PoolBuilder {
    static public macro function build():Array<Field> {
        var fields = Context.getBuildFields();
        var clazz = Context.getLocalClass().get();
        var path = clazz.pack.concat([clazz.name]); // ["exp", "Entity"]

        var extraFields = (macro class {
            static var _pool = new Pool($p{path});
        }).fields;
        return fields.concat(extraFields);
    }
}

这产生以下代码(如可在与exp/Entity.dump -D dump=pretty看到):

static var _pool:exp.Pool<exp.Entity> = new exp.Pool(exp.Entity);

4
投票

如果你更喜欢通过添加的fields.push({...})而不是使用类物化字段,您可以通过使用nullFVar(null, pool)一种触发类型推断:

static public macro function build() : Array<Field> {
    var fields = Context.getBuildFields();
    var clazz = Context.getLocalClass().get();

    var path = clazz.pack.concat([clazz.name]); // ["exp", "Entity"]
    var pool = macro new exp.Pool($p{path});
    fields.push({
        name: "_pool",
        access: [APrivate, AStatic],
        pos: Context.currentPos(),
        kind: FVar(null, pool)
    });

    return fields;
}

这是使用@ gama11伎俩path。这会产生完全相同的代码为@ gama11答案(并可以以同样的方式进行检查)。

© www.soinside.com 2019 - 2024. All rights reserved.