使用Haxe宏实例化带参数的类

Naz*_*lez 6 macros haxe

我试图在Haxe中使用宏制作一些黑暗魔法,我有一个名为的类Entity,我想添加一个带有staticprivate修饰符的池:

Pool.hx:

package exp;

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

    }
}
Run Code Online (Sandbox Code Playgroud)

Entity.hx:

package exp;

@:build(exp.PoolBuilder.build())
class Entity {
    public function new(){}
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我有typePathparams 的问题,并将Class<T>一个参数传递给构造函数.编译器显示以下错误:

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

exp/Entity.hx:4:第4-6行:在此类中定义

有人知道怎么解决吗?

Gam*_*a11 5

像这样手动构建字段有点单调乏味 - 我建议使用类具体化,你可以将字段表示为常规Haxe代码:

macro class {
    static var _pool = new Pool(/* clazz */);
}
Run Code Online (Sandbox Code Playgroud)

这完全绕过了"无效的类型参数数量"问题 - 只需让类型推断成功,并省略类型参数new Pool().

构造函数调用的参数当然是变量的,因此我们仍然需要使用一些表达式.exp.Entity是一个字段表达式,所以我们必须使用$p{}.我们可以通过组合clazz.pack和构造它所需的类型路径clazz.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

static var _pool:exp.Pool<exp.Entity> = new exp.Pool(exp.Entity);
Run Code Online (Sandbox Code Playgroud)

  • 这真的很有帮助,我的生活制作宏现在会更容易!有时我认为"我明白了"但不是真的,很难学习haxe宏的全部内容.谢谢! (3认同)

kLa*_*abz 5

如果您更喜欢通过fields.push({...})而不是使用类具体化来添加字段,您可以通过使用null作为类型 in来触发类型推断FVar(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;
}
Run Code Online (Sandbox Code Playgroud)

这是将@gama11 技巧用于path. 这会生成与@gama11 答案完全相同的代码(并且可以以相同的方式进行检查)。