2009-04-07 44 views
6

Tôi có đối tượng userdata Lua với một loại có thể so sánh nhất định (ví dụ: "stackoverflow.test"). Từ mã C, tôi muốn có thể kiểm tra chính xác loại đó là gì và hoạt động khác nhau tùy thuộc vào kết quả. Có một chức năng tiện dụng tốt đẹp (thay vì như luaL_checkudata, nhưng không có lỗi nếu câu trả lời không phải là những gì bạn muốn) mà hãy để tôi truy vấn tên loại có thể so sánh của userdata? Nếu không, tôi đoán tôi cần phải sử dụng lua_getmetatable, nhưng sau đó tôi là một chút không rõ ràng làm thế nào tôi xác định tên của metatable đó chỉ là được thêm vào ngăn xếp.Truy vấn loại dữ liệu người dùng Lua từ C

Chỉ cần làm rõ: Tôi đang sử dụng Lua 5.1, nơi mà hành vi của luaL_checkudata đã được thay đổi. Tôi hiểu rằng trong 5.0 nó đã không được sử dụng để báo lỗi.

+0

Có vẻ như lua 5.2 đã có những gì bạn đang tìm kiếm: [luaL_testudata] (http://www.lua.org/source/5.2/lauxlib.c.html#luaL_testudata) –

Trả lời

3

Bạn sẽ sử dụng lua_getmetatablelua_equal để thử nghiệm mà các bảng đều giống nhau.

Theo ý kiến ​​của tôi, Lua nên hỗ trợ nhiều hơn cho loại điều mở rộng kiểu này. Hiện tại, nó thực sự thuộc trách nhiệm của hệ thống wrapper Lua/C (++) để làm điều đó.

Trong trình bao bọc tôi đã thực hiện gần đây (như là một phần của dự án thương mại), tôi làm class::instance(L,index) để nhận con trỏ người dùng của một loại cụ thể. Nói cách khác, phương pháp đó kiểm tra xem đó là userdata và metatable cũng đúng. Nếu không, nó trả về NULL.

Cách Lua có thể giúp tất cả điều này là nếu metatable có trường chuẩn cho thông tin loại mở rộng (s.a. __type). Điều này có thể được sử dụng để bản thân số type() sẽ trả về "userdata", "xxx" (hai giá trị, hiện chỉ trả về một giá trị). Điều này sẽ vẫn tương thích với hầu hết mã hiện tại. Nhưng đây chỉ là giả thuyết (trừ khi bạn làm một loại tùy chỉnh() và thực hiện điều này một mình).

0

Tôi vừa xem mã nguồn ở hàm luaL_checkudata và về cơ bản tìm nạp đối tượng userdata có thể sử dụng được bằng cách sử dụng lua_getmetatable. Sau đó nó lấy tên kiểu đã cho từ sổ đăng ký sử dụng lua_getfield và thực hiện cuộc gọi lua_rawequal để so sánh chúng.

5

Bạn luôn có thể lưu trữ trường đánh dấu trong mục có thể so sánh với giá trị userdata nhẹ duy nhất cho mô-đun của bạn.

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; 
} 

Sau đó, bạn có thể sử dụng my_setflavor(L,&green_flavor) để thiết lập các lĩnh vực _flavor của bảng ở phía trên cùng của ngăn xếp, và my_isflavor(L,&red_flavor) để kiểm tra lĩnh vực _flavor của bảng ở phía trên cùng của ngăn xếp. Được sử dụng theo cách này, trường _flavor chỉ có thể nhận các giá trị có thể được tạo bằng mã trong mô-đun có ký hiệu green_flavor trong phạm vi và tìm kiếm trường và kiểm tra giá trị của nó chỉ yêu cầu một bảng tra cứu ngoài việc truy xuất của chính bản thân nó. Lưu ý rằng giá trị của biến green_flavor không quan trọng, vì chỉ địa chỉ của nó thực sự được sử dụng.

Với một số biến hương vị riêng biệt có sẵn để sử dụng làm giá trị sentinal, trường _flavor có thể được sử dụng để phân biệt một số metatables liên quan.

Tất cả điều đó nói, một câu hỏi tự nhiên là "tại sao lại làm điều này?" Sau khi tất cả, metatable có thể dễ dàng chứa tất cả các thông tin cần thiết để có được hành vi thích hợp. Nó có thể dễ dàng giữ chức năng cũng như dữ liệu, và những chức năng này có thể được lấy ra và được gọi từ C cũng như Lua.

2

Các userdata phải có một metatable, do đó, lấy đó; sau đó tìm tên bạn muốn trong sổ đăng ký. Nếu hai đối tượng giống nhau, bạn đã tìm thấy loại bạn đang tìm kiếm.

Bạn có thể gửi loại này bằng mã C, nhưng cho phép tôi nhẹ nhàng đề xuất bạn chỉ định trường có thể thay đổi. Một hàm được lưu trữ trong metatable sẽ thực hiện công việc, nhưng nếu không, nếu bạn hoàn toàn phải switch trong mã C, sau đó chọn tên, sử dụng nó để lập chỉ mục vào metatable, và gán cho mỗi metatable một số nguyên nhỏ bạn có thể bật.

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

và sau đó trong mã 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"); 
Các vấn đề liên quan