【问题标题】:How to return a class instance with an expression macro?如何使用表达式宏返回类实例?
【发布时间】:2020-02-18 04:55:05
【问题描述】:

驱动代码

//---------------- Main.hx ------------------------------------------------------------------
import core.reflection.ReflectionTools;
import core.SomeClass;
class Main{
   public static function main(){
      var s = new SomeClass();
      ReflectionTools.info(s);
   }
}

//---------------- ReflectionTools.hx -----------------------------------------------------
class RelectionTools {
    public static macro function info(obj:Expr):Expr{
        var pos = Context.currentPos();
        var block = [];
        var result:Dynamic;
        var type:Type=Context.typeof(obj);        
        result=(switch(type){
            case TInst(t, params):new RelectionClass(t, params);
            case TEnum(t, params):new ReflectionEnum(t, params);
            case TDynamic(t):new ReflectionDynamic(t);
            case TFun(args, ret):new ReflectionFunction(args, ret);
            case TMono(t):new ReflectionMonomorph(t);
            case TLazy(f):new ReflectionLazy(f);
            case TAbstract(t, params):new ReflectionAbstract(t, params);
            case TType(t, params):new ReflectionTypeDefinition(t, params);
            case TAnonymous(a):new ReflectionAnonymousStructure(a);
        });
        return $v{result};
    }
}

Haxe 编译器:

预期的 Expr 但得到 core.reflection.RelectionClass(有关详细信息,请参阅 dump/decoding_error.txt)

【问题讨论】:

标签: haxe


【解决方案1】:

它不是一个构建宏(它允许返回类实例),而是一个表达式宏。模仿类功能的最佳方法是使用抽象。

/* Solution Description
1. a custom Json abstract with underlying type {} and with implicit   
    casts to underlying type. See Json.hx
2. abstracts which reflect possible Type enums with underlying custom 
   Json abstract and forwards. See example ReflectionPrimitive.hx
   and mimic inheritance by underlying types as superclass 
   see example ReflectionFunction.hx 
3. uses same instantiation code as original class instantiation 
   but now they are abstracts (see PROBLEM(The macro). Solved! */

第 1 步。
具有基础类型 {} 和隐式转换的自定义 Json 抽象 底层类型。

// ---------------- Json.hx ----------------------------------------------
package core.ds.json;
import haxe.Serializer;
import haxe.Unserializer;
import haxe.Json as J;

abstract Json({}) from ({}) to ({}) {
    public inline function new(?data:{}){
        this=data;
        if(this==null){
            this={};
        }
    }
    @:arrayAccess 
    public inline function get(key:String):Dynamic{
        if(exists(key)){
            return Reflect.field(this,key);
        } 
        return null;
    }
    @:arrayAccess 
    public inline function set(key:String, value:Dynamic):Dynamic{
        Reflect.setField(this, key, value);
        return value;
    }   

    public inline function isEmpty(key:String):Bool{
        return !isSet(key) || (exists(key) && (  get(key)=="" || get(key)==''|| get(key)==null || get(key)==0  ));
    }

    public inline function isSet(key:String):Bool{
        return exists(key) && get(key)!=null;
    }

    public inline function exists(key:String):Bool {
        return Reflect.hasField(this, key);
    } 
    @:to
    public inline function toMap():Map<String, Dynamic>{
        var result:Map<String, Dynamic>=new Map<String, Dynamic>();
        var fields:Array<String>=Reflect.fields(this);
        for (f in fields){
            result.set(f, Reflect.field(this, f));
        }
        return result;
    }
    @:to
    public inline function toJsonString():String{
        return J.stringify(this,null," ");
    }

    public inline function values():Array<Dynamic>{
        var result:Array<Dynamic>=[];
        var keys:Array<String>=keys();
        for(k in keys){
            result.push(Reflect.field(this,k));
        }
        return result;
    }

    public inline function keys():Array<String>{
        return Reflect.fields(this);
    }

    public inline function clone():Json{
        return Unserializer.run(Serializer.run(this));
    }

    public var length(get,never):Int;


    private inline function get_length():Int{
        return keys().length;
    }

    public inline function keyValueIterator():KeyValueIterator<String, Dynamic>{
        return toMap().keyValueIterator();
    }


    @:from 
    public static function fromJsonString(json:String):Json{
        return J.parse(json);
    }
    @:from 
    public static function fromMap(map:Map<String, Dynamic>):Json{
        var result={};
        for (k=>v in map){
            Reflect.setField(result, k, v);
        }
        return result;
    }

}

第 2 步。
反映可能的类型枚举的抽象与底层自定义 Json 抽象和转发。请参阅示例 ReflectionPrimitive.hx 并通过底层类型模拟继承作为超类,请参阅示例 ReflectionFunction.hx

//---------------- ReflectionPrimitive.hx ----------------------------------------------

@:forward()
abstract ReflectionPrimitive(core.ds.json.Json) from core.ds.json.Json to core.ds.json.Json{
    public inline function new(nameType:String){
        this=new core.ds.json.Json({data:new core.ds.json.Json(), info:new core.ds.json.Json({nameType:nameType})});
    }
    public var data(get, set):core.ds.json.Json;
    public var info(get, set):core.ds.json.Json;
    private function get_data():core.ds.json.Json {
        return this["data"];
    }
    private function set_data(value:core.ds.json.Json):core.ds.json.Json {
        this["data"]=value;
        return this;
    }
    private function get_info():core.ds.json.Json {
        return this["info"];
    }
    private function set_info(value:core.ds.json.Json):core.ds.json.Json {
        this["info"]=value;
        return this;
    }
 }

模仿继承

//---------------- ReflectionFunction.hx ----------------------------------------------
@:forward(data, info, get, isEmpty, isSet, exists, toMap, toJsonString, values, keys, clone, length, keyValueIterator, fromJsonString, fromMap)
abstract ReflectionFunction(ReflectionPrimitive) from ReflectionPrimitive to ReflectionPrimitive{
    public inline function new(args:Array<{t:Type, opt:Bool, name:String}>, ret:Type){
        this=new ReflectionPrimitive(NameType.FUNCTION);
        var newArgs=new Array<core.ds.json.Json>();
        for(a in args){
           newArgs.push(new core.ds.json.Json(a));
        }
        this.data=this.data.set("args",newArgs).set("ret", ret);
    }
    public var args(get, never):Array<core.ds.json.Json>;
    public var ret(get,never):Type;

    private function get_args():Array<core.ds.json.Json>{
        return this.data.get("args");
    }
    private function get_ret():Type{
        return this.data.get("ret");
    }

}

保持宏不变,它现在可以工作了。

【讨论】:

    【解决方案2】:

    宏是编译时特性,不是运行时特性,你不能返回类实例。相反,你必须返回创建一个新实例的表达式(我没有你的类,所以我在这里使用我的类)

    var type=Context.typeof(obj); 
    return (switch(type){
        case TInst(t, params):macro new MyClass();//RelectionClass(t, params);
        case TEnum(t, params):macro new MyClass();//ReflectionEnum(t, params);
        case TDynamic(t):macro new MyClass();//ReflectionDynamic(t);
        case TFun(args, ret):macro new MyClass();//ReflectionFunction(args, ret);
        case TMono(t):macro new MyClass();//ReflectionMonomorph(t);
        case TLazy(f):macro new MyClass();//ReflectionLazy(f);
        case TAbstract(t, params):macro new MyClass();//ReflectionAbstract(t, params);
        case TType(t, params):macro new MyClass();//ReflectionTypeDefinition(t, params);
        case TAnonymous(a):macro new MyClass();//ReflectionAnonymousStructure(a);
    });
    return macro null;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-05
      • 2011-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-21
      • 2017-01-16
      相关资源
      最近更新 更多