4

私は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.windowを直接実行するとエラーが発生します:

This access invalid outside of instance methods
4

1 に答える 1

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でコールバックを渡す場合、通常は1つから3つの引数を使用して渡します。3つすべての何かは次のようになります。

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

最初のパラメーターは実際の関数です。2番目のパラメーターは、user_dataとしてコールバックに渡す値であり、Valaがコンテキスト情報をコールバックに渡すために使用する値です(これにより、インスタンスメソッド、またはクロージャーとしても機能できます)。3番目のパラメーターは、必要がなくなったときにuser_dataを解放する関数を指定するために使用されます。

[CCode(has_target = false)]が意味するのは、デリゲートにuser_data引数がないため、クロージャーまたはインスタンスメソッドとして使用できないことです。

ジェネリック引数でこれが必要な理由は、ジェネリックが経営幹部レベルで次のように見えるためです。

void foo_bar (gpointer data, GDestroyNotify notify);

最初のパラメーターはジェネリック値として使用するデータであり、2番目のパラメーターは実際にはジェネリック引数が所有されている場合にのみ追加され(Geeのsetメソッドの場合のように)、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;
  }
}
于 2012-07-03T17:30:55.053 に答える