macros - 在使用 haxe 宏构建的函数中使用局部变量

标签 macros haxe

我有一个 LangBuilder宏类;它用于构建 langObjects:Map<String, Dynamic>在编译时使用各种语言的文本,并通过 @:build 将此结构注入(inject)类中宏。 Map 的每个项目都有一个字段用于支持的每种语言。所以结果是:

@:build(LangBuilder.build())
class Lang{}

trace(Lang.langObjects["hello-world"].en); //outputs "Hello World!"
trace(Lang.langObjects["hello-world"].it); //outputs "Ciao Mondo!"

这很完美,但我想我可以更干净地隐藏 langObjects使用函数的结构 getLangText带有参数的文本 ID(例如 "hello-world" )和语言代码(例如 "it" )。

所以我正在尝试将此功能添加到类中:

public static function getLangText(id:String, lang:String)

其非宏版本可以表示为:

public static function getLangText(id:String, lang:String){
    var _langObj_id = langObjects[id];
    switch(lang){
        case "it":
            return _langObj_id.it;
        case "en":
            return _langObj_id.en;
    }
    return "Missing Translation";

如果我用这段代码将这个函数翻译成一个宏:

var code = macro {
  var _langObj_id = langObjects[$i{"id"}];
  switch($i{"lang"}){
    case "it":
      return _langObj_id.it;
    case "en":
      return _langObj_id.en;
  }
  return "Missing translation";
};

var myFunc:Function = {
  args: [{
    name: "id",
    type: TPath({name: "String", pack: []}),
    meta: null
  },
  {
    name: "lang",
    type: TPath({name: "String", pack: []}),
    meta: null
  }],
  ret: (macro:String),
  expr: macro $code
};

fields.push({
  pos: Context.currentPos(),
  name: "getLangText",
  meta: null,
  kind: FieldType.FFun(myFunc),
  doc: null,
  access: [Access.APublic, Access.AStatic]
});

...它没有问题。但是我想知道如果没有 switch 怎么写,使它更灵活,并学习一些关于 haxe 宏的知识。我见过一些示例,其中可以使用 $p{} 在宏中访问字段或 object.$fieldName .然而,haxe 手册警告说,第二种形式只能用于简单的标识符;例如 object.${fieldName}行不通。

所以我试试这段代码:

var code = macro {
  var l:String = $i{"lang"};
  var _langObj_id = langObjects[$i{"id"}];
  return _langObj_id.$l;
};

编译报错

Unknown identifier : l

在包含 return _langObj_id.$l; 的行上.

然后我尝试使用 $p{}具体化:

var code = macro {
  var _langObj_id = langObjects[$i{"id"}];
  return macro $p{["_langObj_id", $i{"lang"}]};
};

但错误类似:

Unknown identifier : lang

我肯定可以改变 langObjects结构为 Map<String, Map<String, String>>然后将代码更改为:

var code = macro {
  return macro langObjects[$i{"id"}][$i{"lang"}];
};

我认为这行得通,但现在我正试图理解为什么 _langObj_id.$lang$p{["_langObj_id", $i{"lang"}]}行不通,在这种情况下访问字段的正确方法是什么。

最佳答案

lang 参数的值在编译/宏时是未知的,所以我不知道如何生成像 langObjects["mytext"这样的字段访问表达式].zh.在实际调用 getLangText() 时,lang 可以是 "en" 或任何其他内容。因此,这仍然需要一个 switch-case、if-else-chain 或反射来处理所有可能的值。

如果 getLangText() 不是由构建宏创建,而是表达式宏/宏函数,则函数调用将在编译时求值, 并替换为它返回的表达式。这将允许您根据参数生成适当的字段访问表达式。它可能看起来像这样:

class Macro {
    public static var langObjects = ["mytext" => {en: "hello", de: "hallo"}];

    public static macro function getLangText(id:String, lang:String) {
        return macro {
            var langObject = Macro.langObjects[$v{id}];
            langObject.$lang;
        }
    }
}
class Main {
    static function main() {
        trace(Macro.getLangText("mytext", "en"));
        trace(Macro.getLangText("mytext", "de"));
    }
}

在 JS 目标上编译为以下内容:

Main.main = function() {
    var langObject = Macro.langObjects.get("mytext");
    console.log("source/Main.hx:3:",langObject.en);
    var langObject1 = Macro.langObjects.get("mytext");
    console.log("source/Main.hx:4:",langObject1.de);
};

也许这就是您要找的东西?在不知道您要解决什么问题的情况下很难说。

关于macros - 在使用 haxe 宏构建的函数中使用局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53472382/

相关文章:

macros - CL 样式宏中的多个(定义)

arrays - 如何在haxe中将数组初始化为给定大小

flash - Flash 3D 引擎的比较

vba - 某些字符在 vba 宏中会丢失格式,而其他字符则不会

javascript - 使用 openfl 嵌入 .js 代码

HaxeFlixel 意想不到的 & (amp) 角色

Haxe - 打印命令行参数

rust - 基于宏规则生成元组索引!重复扩展

c - 是否应该使用宏而不是灵活的数组成员?

c - 帮助2个C宏