6

特定のメタテーブルタイプ(例)のLuauserdataオブジェクトがあります"stackoverflow.test"。Cコードから、それがどのタイプであるかを正確に確認し、結果に応じて異なる動作をすることができるようにしたいと思います。luaL_checkudataユーザーデータのメタテーブルタイプ名をクエリできる便利な関数(のようなものですが、答えが希望どおりでない場合はエラーが発生しません)はありますか?そうでない場合は、を使用する必要があると思いますlua_getmetatableが、スタックに追加されたばかりのメタテーブルの名前をどのように決定するかが少しわかりません。

明確にするために:luaL_checkudataの動作が変更されたLua5.1を使用しています。5.0ではエラーが発生していなかったことを理解しています。

4

4 に答える 4

5

モジュールに固有の軽いユーザーデータ値を使用して、メタテーブルにマーカーフィールドを常に格納できます。

static const char *green_flavor = "green";
...
void my_setflavor(lua_State *L, void *flavor) {
  lua_pushlightuserdata(L,flavor);
  lua_pushlstring(L,"_flavor");
  lua_rawset(L,-3);
}

void my_isflavor(lua_State *L, void *flavor) {
  void *p = NULL;
  lua_pushlstring(L,"_flavor");
  lua_rawget(L,-2);
  p = lua_touserdata(L,-1);
  lua_pop(L,1);
  return p == flavor;
}

次にmy_setflavor(L,&green_flavor)、スタックの一番上にあるテーブルの _flavor フィールドを設定し、スタックの一番上にあるmy_isflavor(L,&red_flavor)テーブルの _flavor フィールドをテストするために使用できます。

このように使用すると、_flavor フィールドは、スコープ内にシンボル green_flavor を持つモジュール内のコードによって作成できる値のみを受け取ることができ、フィールドのルックアップとその値のテストには、メタテーブル自体の取得とは別に、1 つのテーブル ルックアップのみが必要でした。 . 実際にはアドレスのみが使用されるため、変数 green_flavor の値は重要ではないことに注意してください。

センティナル値として使用できるいくつかの異なるフレーバー変数を使用すると、_flavor フィールドを使用して、いくつかの関連するメタテーブルを区別できます。

とはいえ、当然の疑問は「なぜこれを行うのか」ということです。結局、メタテーブルには、適切な動作を得るために必要なすべての情報を簡単に含めることができます。データだけでなく関数も簡単に保持でき、それらの関数は Lua だけでなく C からも取得して呼び出すことができます。

于 2009-04-08T01:43:45.603 に答える
2

ユーザーデータにはメタテーブルが必要なので、それを取得してください。次に、レジストリで必要な名前を検索します。2 つのオブジェクトが同一であれば、探しているタイプが見つかりました。

この型を C コードでディスパッチすることもできますが、代わりにメタテーブルのフィールドを指定することをお勧めします。メタテーブルに格納された関数がその仕事を行うべきですが、そうでない場合switch、C コードで絶対に必要な場合は、名前を選び、それを使用してメタテーブルにインデックスを付け、各メタテーブルにスイッチを入れることができる小さな整数を割り当てます。

meta1.decision = 1
meta2.decision = 2
meta3.decision = 3

そしてあなたのCコードで

if (lua_getmetatable(L, 1)) {
  lua_getfield(L, -1, "decision");
  if (lua_isnumber(L, -1)) {
    switch ((int) lua_tonumber(L, -1)) {
       case 1: ... ; break;
       case 2: ... ; break;
       case 3: ... ; break;
    }
    return 0;
  }
}
return luaL_error(L, "Userdata was not one of the expected types");
于 2009-04-09T02:05:56.760 に答える
0

関数のソースコードを見たところ、luaL_checkudata基本的にはを使用してuserdataオブジェクトのメタテーブルをフェッチしますlua_getmetatable。次に、を使用してレジストリから指定されたタイプ名をフェッチし、それらを比較するためlua_getfieldの呼び出しを実行します。lua_rawequal

于 2009-04-07T18:17:30.233 に答える