什么不能创建委托没有目标实例方法或闭包意味着什么

时间:2012-07-03 15:24:33

标签: vala

我正在使用vala。 这是给出编译时错误的源代码:

private Gee.HashMap<string,VoidFunc> fill_actions()
{
    var actions = new Gee.HashMap<string,VoidFunc>();
    MainWindow win = window;
    actions["t"] = () => _puts(win.title);
    return actions;
}

首先,我尝试直接访问this.window,但这又产生了一个错误,所以我尝试使用本地范围变量。

直接执行此操作时出错。窗口:

This access invalid outside of instance methods

1 个答案:

答案 0 :(得分:9)

听起来VoidFunc是用[CCode(has_target = false)]声明的。这意味着没有传递任何上下文信息,而AFAIK是委托作为泛型类型参数工作的唯一方式。原因是C的限制,所以假设VoidFunc看起来像这样:

[CCode (has_target = false)]
public delegate void VoidFunc ();

你在C中得到的是这样的:

typedef void (*VoidFunc)();

如果你没有[CCode(has_target = false)],那么就像这样的东西:

typedef void (*VoidFunc)(gpointer user_data);

当您在C中传递回调时,通常使用一到三个参数进行回调。这三种东西看起来像这样:

void foo (VoidFunc void_func, gpointer user_data, GDestroyNotify notify);

第一个参数是实际功能。第二个参数是作为user_data传递给回调的值,也是Vala用于将上下文信息传递给回调的内容(这使得它可以充当实例方法,甚至是闭包)。第三个参数用于指定在不再需要时释放user_data的函数。

[CCode(has_target = false)]意味着委托没有user_data参数,因此不能用作闭包或实例方法。

对于泛型参数,这是必要的原因是泛型在C级看起来像这样:

void foo_bar (gpointer data, GDestroyNotify notify);

第一个参数是你想要用作通用值的数据,第二个参数实际上只有在拥有泛型参数时才会被添加(就像在Gee中设置方法的情况一样),并且被调用当不再需要user_data时,user_data作为参数。

正如您所看到的,当尝试使用委托作为泛型时,无处放置user_data参数,这就是为什么Vala只允许没有目标的委托是泛型参数。

解决方案基本上是将委托包装在一个类中:

public delegate void VoidFunc ();

public class YourClass {
  private class VoidFuncData {
    public VoidFunc func;

    public VoidFuncData (owned VoidFunc func) {
      this.func = (owned) func;
    }
  }

  private Gee.HashMap<string,VoidFuncData> fill_actions() {
    var actions = new Gee.HashMap<string,VoidFuncData>();
    string win = "win";
    actions["t"] = new VoidFuncData (() => GLib.debug (win));
    return actions;
  }
}