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

Macros 在用haxe宏构建的函数中使用局部变量,macros,haxe,Macros,Haxe,我有一个LangBuilder宏类;它用于在编译时构建各种语言文本的langObjects:Map,并通过@:build宏将此结构注入类中。地图的每个项目都有一个字段,用于支持的每种语言。因此,结果是: @:build(LangBuilder.build()) class Lang{} trace(Lang.langObjects["hello-world"].en); //outputs "Hello World!" trace(Lang.langObjects["hello-world"]

我有一个
LangBuilder
宏类;它用于在编译时构建各种语言文本的
langObjects:Map
,并通过
@:build
宏将此结构注入类中。地图的每个项目都有一个字段,用于支持的每种语言。因此,结果是:

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

trace(Lang.langObjects["hello-world"].en); //outputs "Hello World!"
trace(Lang.langObjects["hello-world"].it); //outputs "Ciao Mondo!"
这非常有效,但我认为我可以使用带有文本id(例如
“hello world”
)和语言代码(例如
“it”
)的参数的函数
getLangText
)来隐藏
langObjects
结构

因此,我尝试将此函数添加到类中:

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]
});
var code = macro {
  var l:String = $i{"lang"};
  var _langObj_id = langObjects[$i{"id"}];
  return _langObj_id.$l;
};
。。。它毫无问题地工作。然而,我想知道如何在没有
开关的情况下编写它,使它更灵活,并了解一些关于haxe宏的知识。我见过一些例子,其中可以使用
$p{}
对象在宏中访问字段。$fieldName
。然而,haxe手册警告说,第二种形式只能用于简单的标识符;例如,
对象。${fieldName}
将不起作用

因此,我尝试以下代码:

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]
});
var code = macro {
  var l:String = $i{"lang"};
  var _langObj_id = langObjects[$i{"id"}];
  return _langObj_id.$l;
};
编译器给出了一个错误

未知标识符:l

在包含
返回_langObj_id.$l的行上

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

var code = macro {
  var _langObj_id = langObjects[$i{"id"}];
  return macro $p{["_langObj_id", $i{"lang"}]};
};
但错误是相似的:

未知标识符:lang

我当然可以将
langObjects
结构更改为
Map
,然后将代码更改为:

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

我认为这是可行的,但现在我正试图理解为什么
\u langObj\id.$lang
$p{[“\u langObj\u id”,$I{“lang”}]}
都不起作用,在这种情况下访问字段的正确方法是什么。

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

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

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;
        }
    }
}
在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);
};

也许这就是你要找的?如果不知道您要解决的问题,很难说。

谢谢您的回答。我更新了问题,以便更好地解释我要做的事情。使用嵌套映射显然是更实用的方法。。。你明白我回答的第一部分了吗?当您只需要知道在运行时字段的名称时,就不能在编译时生成字段访问。您尝试的两种具体化语法都要求
lang
是宏的
code
部分之外的变量。由于不存在,您将以“未知标识符”结束。我知道,
lang
在构建时是未知的。。。因此,除了通过
开关/if-then-else/reflection
在这里列出各种条件外,没有办法动态访问字段?嗯,在运行时动态访问字段的常用方法是:反射。正如您所说,它要么是一个带有所有可能值的
开关(或if-else链)。在编译时将函数替换为实际字符串的替代宏也是整洁的。唉,我不能使用它,因为我需要语言在运行时是可变的。也许我可以把它和嵌套的地图结构合并起来。。。