我有一个独特的情况。出于各种原因,主要是与可以为空的stringly typed遗留系统进行互操作,以及我目前不会进入的各种其他需求,我已经确定了一个自定义的@:enum摘要,看起来像这样:
@:enum abstract MyEnum(Null<Int>) {
public var A = 0;
public var B = 1;
public var C = 2;
public var D = 3;
public var E = 4;
public var F = 5;
public var G = 6;
@:from private static function fromString (value:String):MyEnum {
return switch (value) {
case "a": A;
case "b": B;
case "c": C;
case "d": D;
case "e": E;
case "f": F;
case "g": G;
default: null;
}
}
@:to private static function toString (value:Int):String {
return switch (value) {
case A: "a";
case B: "b";
case C: "c";
case D: "d";
case E: "e";
case F: "f";
case G: "g";
default: null;
}
}
}
然而,这需要输入大量令人讨厌的东西,并且在添加和删除成员时,很容易发生手动错误。显然,这遵循一个超级可预测的模式,用宏来构造似乎是一件好事,但我对haxe宏很糟糕。
有人可以解释我如何使用宏来构建这个枚举,以便我所提供的只是一个字段名列表吗?
伪代码:
@:enum abstract MyEnum = doTheMacroMagic(["A","B","C","D","E","F","G"]);
逻辑步骤是:
我认为像这样一个简单的实际例子可能最终使haxe宏&#34;点击&#34;对我来说,如果我能在行动中看到它。
答案 0 :(得分:2)
Flixel处理类似于FlxKey
和FlxMacroUtil.buildMap()
的类的用例。此表达式宏查找它在摘要中找到的所有大写内联变量并从中生成Map<String, EnumType>
,其中键是字段名称,值是字段值(或者如果{{1}则相反}是invert
)。
true
我认为这是一个很好的起点。如果您想要生成整个@:enum
abstract FlxKey(Int) from Int to Int
{
public static var fromStringMap(default, null):Map<String, FlxKey>
= FlxMacroUtil.buildMap("flixel.input.keyboard.FlxKey");
public static var toStringMap(default, null):Map<FlxKey, String>
= FlxMacroUtil.buildMap("flixel.input.keyboard.FlxKey", true);
var A = 65;
var B = 66;
// more keys...
@:from
public static inline function fromString(s:String)
{
s = s.toUpperCase();
return fromStringMap.exists(s) ? fromStringMap.get(s) : NONE;
}
@:to
public inline function toString():String
{
return toStringMap.get(this);
}
}
,则需要abstract
宏。
回答后续问题,如何生成字段:使用构建宏实际上非常简单:
@:build
@:enum
@:build(Macro.createVariables(["A", "B", "C", "D", "E"]))
abstract Generated(Int)
{
}
(明智地拥有自己的文件以避免处理Macro.hx
条件):
#if macro
您会注意到package;
import haxe.macro.Context;
import haxe.macro.Expr;
class Macro
{
public static macro function createVariables(varNames:Array<String>):Array<Field>
{
// get the current fields of the calling type (empty array in this case)
var fields = Context.getBuildFields();
for (i in 0...varNames.length)
// create a custom variable and add it to the fields
fields.push(createVariable(varNames[i], i));
return fields;
}
private static function createVariable(name:String, value:Int):Field
{
return {
name: name,
doc: null,
meta: [],
access: [Access.APublic, Access.AStatic, Access.AInline],
kind: FieldType.FVar(macro:Int, macro $v{value}),
pos: Context.currentPos()
}
}
}
自动完成中显示的字段。您还可以通过在执行AST转储时查看Generated.
来查看生成的内容。