@: универсальный только для некоторых параметров типа - PullRequest
1 голос
/ 11 декабря 2019

Если я хочу создать класс с двумя параметрами типа, и я хочу специализированную реализацию для каждого используемого параметра первого типа, но я не хочу его для параметра второго типа.

Например, я хочу свою собственную карту

@:generic @:remove
class MyMap {
    public var map: Map<K, V> = new Map();
    public function new() {}
}

Это создаст реализацию для каждой использованной комбинации K и V. Но я хочу разные реализации только для K.

Я пытался создать класс abstract over @:generic с необходимым параметром типа или расширить такой класс. Но это не работает. В обоих случаях haxe-компилятор создает класс MyMapBase и вообще не создает этот класс.

@:generic @:remove
class MyMapBase<K> {
    public var map: Map<K, Dynamic> = new Map();
    public function new() {}
}

class MyMap1<K, V> extends MyMapBase<K> {
}

abstract MyMap2<K, V>(MyMapBase<K>) {
    public function new() {
        this = new MyMapBase();
    }
}

Ответы [ 2 ]

0 голосов
/ 12 декабря 2019

Тебе вообще не нужен твой собственный класс. А поскольку ваши значения хранятся как динамические, вам нужен только один экземпляр карты для каждого типа ключа. Если это нежелательно, вы можете изменить его обратно на количество экземпляров на значение, но тогда зачем использовать динамические значения? В любом случае, вот версия карты, которая работает для всех целей.

@:multiType
abstract MyMap<K, V>(Map<K, Dynamic>) {

    public function new();

    public inline function set(k:K, v:V) this.set(k, v);
    public inline function get(k:K) return this.get(k);

    public static var string_map = new Map<String, Dynamic>();
    @:to static inline function toStringMap<K:String>(t:Map<K, Dynamic>) {
        return string_map;
    }

    public static var int_map = new Map<Int, Dynamic>();
    @:to static inline function toIntMap<K:Int>(t:Map<K, Dynamic>) {
        return int_map;
    }

    public static var object_map = new Map<{}, Dynamic>();
    @:to static inline function toObjectMap<K:{}>(t:Map<K, Dynamic>) {
        return object_map;
    }
}
    var i = new MyMap<String, Int>();
    i.set("zero", 0);
    trace(Type.getClassName(Type.getClass(i))); //haxe.ds.StringMap
    trace(i); // {zero => 0}
    var s = new MyMap<String, String>();
    s.set("one", "1");
    trace(Type.getClassName(Type.getClass(s))); //haxe.ds.StringMap
    trace(s); // {zero => 0, one => 1}
    // var v:Int = i.get("one") will fail on Java and HL
    // we let v to infer as Null<Dynamic> instead
    var v = i.get("one");
    trace(v);
0 голосов
/ 12 декабря 2019

Вот мое решение. Я использовал @: multiType abstract. Эта функция плохо документирована в haxe, но можно посмотреть на реализацию Map.

@:generic @:remove
class MyMapImpl<K> implements IMyMap<K, Dynamic> {
    public var map: Map<K, Dynamic> = new Map();
    public function new() {}
}

interface IMyMap<K, V> {
    public var map: Map<K, V>;
}

@:multiType(K)
abstract MyMap<K, V>(IMyMap<K, V>) {

    public function new();

    public var map(get, never): Map<K, V>;

    inline function get_map(): Map<K, V> {
        return this.map;
    }

    @:to static inline function toStringMap<K:String, V>(t:IMyMap<K, V>):MyMapImpl<String> {
        return cast new MyMapImpl<String>();
    }

    @:to static inline function toIntMap<K:Int, V>(t:IMyMap<K, V>):MyMapImpl<Int> {
        return cast new MyMapImpl<Int>();
    }
}


class Main {
    static function main() {
        var m = new MyMap<String, Int>();
        trace(Type.getClassName(Type.getClass(m))); //MyMapImpl_String
        trace(Type.getClassName(Type.getClass(m.map))); //haxe.ds.StringMap

        var m = new MyMap<String, String>();
        trace(Type.getClassName(Type.getClass(m))); //MyMapImpl_String
        trace(Type.getClassName(Type.getClass(m.map))); //haxe.ds.StringMap

        var m = new MyMap<Int, Int>(); 
        trace(Type.getClassName(Type.getClass(m))); //MyMapImpl_Int
        trace(Type.getClassName(Type.getClass(m.map))); //haxe.ds.IntMap
    }
}
...