在Haxe中使用函数作为映射键

时间:2016-03-25 18:23:02

标签: haxe

我想在Map中使用函数作为键:

var timers : Map<Void->Void, snow.api.Timer>;

但是Haxe不会编译:

  

抽象地图没有@:接受IMap&lt; Void - &gt;的函数Void,snow.api.Timer&gt;

有办法做到这一点吗?

2 个答案:

答案 0 :(得分:3)

编写自定义实现很容易:

import haxe.Constraints;

class FunctionMap<K:Function,V> implements IMap<K,V> {
  private var _keys : Array<K>;
  private var _values : Array<V>;

  public function new () {
    _keys = [];
    _values = [];
  }

  public function get(k:K):Null<V> {
    var keyIndex = index(k);
    if (keyIndex < 0) {
        return null;
    } else {
        return _values[keyIndex];
    }
  }

  public function set(k:K, v:V):Void {
    var keyIndex = index(k);
    if (keyIndex < 0) {
        _keys.push(k);
        _values.push(v);
    } else {
        _values[keyIndex] = v;
    }
  }

  public function exists(k:K):Bool {
    return index(k) >= 0;
  }

  public function remove(k:K):Bool {
    var keyIndex = index(k);
    if (keyIndex < 0) {
        return false;
    } else {
        _keys.splice(keyIndex, 1);
        _values.splice(keyIndex, 1);
        return true;
    }
  }

  public function keys():Iterator<K> {
    return _keys.iterator();
  }

  public function iterator():Iterator<V> {
    return _values
        .iterator();
  }

  public function toString():String {
    var s = new StringBuf();
    s.add("{");
    for( i in 0..._keys.length ) {
        s.add('<function>');
        s.add(" => ");
        s.add(Std.string(_values[i]));
        if( i < _keys.length - 1 )
            s.add(", ");
    }
    s.add("}");
    return s.toString();
  }   


  private function index(key:K) : Int {
    for (i in 0..._keys.length) {
        if (Reflect.compareMethods(key, _keys[i])) {
            return i;
        }
    }
    return -1;
  }}

http://try.haxe.org/#DdF31

答案 1 :(得分:1)

我刚刚在try.haxe.org中尝试了这个,编译器似乎不喜欢它,所以我猜测答案是“不”。

你可以通过一些cleverness来解决这个问题:

class Test {
    static function main() {
        var map:Map<VoidVoid,String>;
        map = new Map<VoidVoid,String>();
        var thing = {func:foo};
        map.set(thing,"bar");
        trace(map.get({func:foo}));  //fails
        trace(map.get(thing));       //succeeds;
    }

    static function foo():Void
    {

    }
}

typedef VoidVoid = {
    var func:Void->Void;
}

但这不是一个理想的解决方案,因为将它包装在类似的类型中会使它失败,如果它不是完全相同的实例,即使里面的值是相同的。

我也试过制作一个Map<Dynamic,String>,因为你可以填充函数引用,但这也不起作用。

此时我应该问,你想用这种方式解决什么问题?也许它可以通过其他方式更好地解决。