【问题标题】:How to cast to dynamic type at generic function?如何在泛型函数中转换为动态类型?
【发布时间】:2016-06-09 21:44:34
【问题描述】:

我有一个基本的原型类:

class CItemProto {

    public var id:Int;

    public var count:Int;

    ...
}

以及一些不同类型的扩展:

class CItemThing extends CItemProto { ... }
class CItemResource extends CItemProto { ... }
class CItemRecipe extends CItemProto { ... }

...等等。每个 item 实例都有唯一的 id,所以我可以通过简单的 IntMap 访问将我的所有东西存储在一个库存类中:

class CInventory {

    var mMap:IntMap<CItemProto>;

    public function new() {
        mMap = new IntMap();
    }

    public inline function set(item:CItemProto) { mMap.set(item.id, item); }

    public function get<T:CItemProto>(id:Int):T {
        var item = mMap.get(aId);
        if (Std.is(item, Class<T>)) // it doesn't work saying Unexpected )
            return cast item;
        return null;
    }

}

我的意思是使用 get() 访问器和一些项目 id 和这个项目类型,如果我在类型选择中出错,方法应该返回 null 值。例如:

// should return instance of CItemThing if it exists or null in the other way
var thing:CItemThing = inventory.get(123);

但它不起作用。如果我请求错误的类型,简单的不安全转换会失败,安全转换需要 Dynamic 类型而不是通用 T 替换。我应该怎么做才能按类型过滤请求的项目?当然,我可以将类型作为第二个参数传递,但它看起来庞大且过多。

更新我找到了主题How to look for a class type in an array using generics,所以我的问题毫无意义。我将传递所需的类型作为第二个参数。

【问题讨论】:

    标签: generics casting haxe


    【解决方案1】:

    我会使用这样的东西:

    public function safeGetAs<T:CItemProto>(id:Int, c:Class<T>):T {
        var v = mMap.get(id);
        if (Std.is(v, c)) return cast v;
        return null;
    }
    

    然后你必须显式键入你想要的,因为这不是编译时可以解决的。打字也更有意义:

    inventory.set(new CItemThing(1));
    inventory.set(new CItemResource(2));
    
    var a = inventory.safeGetAs(1, CItemThing);
    trace(a); // returns instance
    $type(a); // expected: CItemThing. is: CItemThing. 
    
    var b = inventory.safeGetAs(2, CItemThing);
    trace(b); // returns null
    $type(b); // expected: CItemThing. is: CItemResource. 
    

    演示:http://try.haxe.org/#65792

    【讨论】:

    • 谢谢,我也做了同样的解决方案。现在我看到将类作为预期数据类型传递并不是缺点。
    • 您可以使用return Std.instance(v, c)替换if..return cast...return null
    【解决方案2】:

    我做了一个非常丑陋的解决方法:

    typedef Constructible = {
        function new():Void;
    }
    
    @:generic
    public function get<T:(CItemProto,Constructible)>(id:Int):Null<T> {
        var typed = new T();
        var item:CItemProto = mMap.get(id);
        if (Std.is(item, Type.getClass(typed)))
            return cast item;
        return null;
    }
    

    现在我可以请求任何类型的项目,例如:

    var thing:CItemThing = inventory.get(111);
    var resource:CItemResource = inventory.get(222);
    

    但你不应该这样做。

    【讨论】:

    • 创建一个实例来获取它的类?为什么甚至发布一个以“但你不应该这样做”结尾的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多