如何在泛型函数中转换为动态类型?

时间:2016-06-09 21:44:34

标签: generics casting haxe

我有一个基本的原型类:

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

但它不起作用。如果我请求错误类型,安全演员要求动态类型而不是通用 T 替换,则简单的不安全强制转换会失败。我应该怎么做才能按类型过滤所请求的项目?因为我可以传递类型作为第二个参数,但它看起来笨重而且过分。

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:-1)

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

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

但你不应该这样做。