0

これは、ここにあるネストされた登録済み C 関数に関する以前の質問への一種のフォローアップです: Trying to call a function in Lua with nested tables

前の質問から、次のようなネストされた関数を追加する答えが得られました。

dog.beagle.fetch()

また、次のような変数をそのレベルで使用したいと考えています。

dog.beagle.name
dog.beagle.microchipID

この文字列と数値を C で割り当てて、Lua からアクセスできるようにします。したがって、C コードでは、変数は次のように定義できます。

int microchipIDNumber;
char dogname[500];

C 変数は Lua の代入によって更新する必要があり、その値は等号の右側にあるときに Lua によって取得される必要があります。__index および __newindex メタメソッドの概念を試してみましたが、変数への Lua パスに 2 つのドットがあると、すべてがうまくいかないようです。おそらく 2 つのドットを使用してより複雑にしていることはわかっていますが、Lua コードでの構成がはるかに読みやすくなっています。また、microchipIDNumber の値が変化したときにハードウェアを起動する必要があるため、割り当てのイベントも取得する必要があります。値を設定している間に __newindex を介してこれを行うことができると思います。

ネストを達成するためにメタテーブルとメソッドをどのようにコーディングするかについてのアイデアはありますか? 以前の関数宣言が Lua を混乱させているためでしょうか?

4

1 に答える 1

1

Luaのコロン演算子 ( :) は、関数に対してのみ使用されます。次の例を検討してください。

meta = {}
meta["__index"] = function(n,m) print(n) print(m) return m end
object = {}
setmetatable(object,meta)
print(object.foo)

index 関数は、渡された 2 つの引数を単純に出力し、2 番目の引数を返します (単に実行object.fooすると構文エラーになるため、2 番目の引数も出力します)。出力はtable: 0x153e6d0 foo foo新しい行になります。変数__indexとその名前を検索しているオブジェクトを取得します。で置き換えるobject.fooと、次のobject:fooようになります。

input:5: function arguments expected near ')'

これは:inobject:fooが のシンタックス シュガーでobject.foo(object)あるためです。そのため、Lua は関数呼び出しに引数を提供することを期待しています。引数 ( object:foo("bar")) を指定した場合、次のようになります。

table: 0x222b3b0
foo
input:5: attempt to call method 'foo' (a string value)

したがって、__index関数は引き続き呼び出されますが、引数は渡されません。Lua は単に戻り値を呼び出そうとします。:したがって、メンバーには使用しないでください。

それはさておき、Lua と C の間で変数を同期する方法を見てみましょう。これは実際にはかなり複雑で、さまざまな方法があります。__index1 つの解決策は、とを組み合わせて使用​​することです__newindex。C で構造体を作成している場合は、beagleこれらの C 関数を作成し、C 構造体へのポインターを上位値として持つ C クロージャーとして Lua テーブルのメタテーブルにプッシュすることをお勧めします。Lua の一般的なクロージャーに関する情報については、これを参照しください。lua_pushcclosure

参照できる単一の構造体がない場合はvariableName-variableLocation、C 側で何らかの形でペアを格納し、それぞれがどのような型であるかを知る必要があるため、さらに複雑になります。実際の Lua テーブルでそのようなリストを維持できるのでdog.beagle、変数名から 1 つまたは 2 つの何かへのマップになります。この「何か」にはいくつかのオプションがあります。まず、1 つのライト ユーザー データ (つまり、C ポインター) ですが、それが何を指しているのかを理解するという問題が発生します__index__newindex. もう 1 つのオプションは、2 つの関数/クロージャーをプッシュすることです。処理する必要がある型 (数値、文字列、テーブルなど) ごとに C 関数を作成し、変数ごとに適切な関数をプッシュするか、指定されている型をパラメーターとして受け取る uber-closure を作成することができます。プッシュするアップ値を変えるだけです。この場合、関数__index__newindex関数は、指定された変数名に対応する適切な関数を検索して呼び出すだけなので、おそらく Lua で実装するのが最も簡単でしょう。

2 つの関数の場合、次のdog.beagleようになります (実際の Lua 構文ではありません)。

dog.beagle = {
  __metatable = {
    __index = function(table,key)
      local getFunc = rawget(table,key).get
      return getFunc(table,key)
    end

    __newindex = function(table,key,value)
      local setFunc = rawget(table,key).set
      setFunc(table,key,value)
    end
  }
  "color" = {
    "set" = *C function for setting color or closure with an upvalue to tell it's given a color*,
    "get" = *C function for getting color or closure with an upvalue to tell it to return a color*
  }
}

上記に関する注意事項: 1. オブジェクトの__metatableフィールドを直接設定しないでください。実際のメタテーブルを非表示にするために使用されます。setmetatable(オブジェクト、メタテーブル) を使用します。2. の使用法に注意してくださいrawget。そうしないと、オブジェクトのフィールドを内部から取得しようとすると__index無限再帰になるため、これが必要です。rawget(table,key)3. イベント return で、または戻り値に/メンバーnilがない場合は、もう少しエラー チェックを行う必要があります。getset

于 2012-11-23T09:14:18.307 に答える