【问题标题】:Using functions as map keys in Haxe在 Haxe 中使用函数作为映射键
【发布时间】:2025-12-26 18:55:06
【问题描述】:

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

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

但 Haxe 不会编译:

抽象地图没有接受 IMap Void, snow.api.Timer>

的 @:to 函数

有没有办法做到这一点?

【问题讨论】:

    标签: haxe


    【解决方案1】:

    编写自定义实现很容易:

    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

    【讨论】:

    • 是的,我的第二个意图是使用两个数组并将它们与一个用于 key 和第二个用于 value 同步。所以没有办法做到这一点?感谢您的代码和实施:)
    【解决方案2】:

    我刚刚在 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;
    }
    

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

    我也尝试过创建Map&lt;Dynamic,String&gt;,因为您可以在其中填充函数引用,但这也不起作用。

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

    【讨论】:

    • 感谢您的检查,在 Unity3D 中,您可以使用 Coroutine。要调用协程,您可以调用 StartCoroutine(myFnct()),要停止它,您可以调用 StopCoroutine(myFnct())。我想在 haxe 中重现相同的行为。我有一个可以添加/删除功能的经理。我发现 mapVoid, ...> 是在某些功能上分配某些行为的好方法。而且我喜欢避免碰撞的结构,而不是使用带有函数名称的映射来识别它。也许它存在更好的解决方案来做到这一点。感谢您的帮助