2011-02-23 34 views
1

你好,我有這似乎工作,但我不知道爲什麼下面的代碼位 - 我已經建立了一個識別TestClass如下盧阿元表登記

class testclass { 
    int ivalue; 
public: 
    int getivalue(); 
    void setivalue(int &v); 
}; 

,然後註冊的識別TestClass (實際功能中遺漏了一些位,但它們非常基本)。這是我沒有遵循的metatables的註冊。 (etivalue和setivalue是叫同一個名字的類函數的C函數)

static const struct luaL_Reg arraylib_f [] = { 
    {"new", new_testclass}, 
    {NULL, NULL} 
}; 

static const struct luaL_Reg arraylib_m [] = { 
    {"set", setivalue}, 
    {"get", getivalue}, 
    {NULL, NULL} 
}; 

int luaopen_testclass (lua_State *L) { 
    luaL_newmetatable(L, "LuaBook.testclass"); 
    lua_pushvalue(L, -1); /* duplicates the metatable */ 
    lua_setfield(L, -2, "__index"); 
    luaL_register(L, NULL, arraylib_m); 
    luaL_register(L, "testclass", arraylib_f); 
    return 1; 
} 

我不明白的是我加入的功能到__index的元表,但 當我運行

a = testclass.new() 
a:set(10) 
print(a:get()) 

然後它按預期工作。我不明白的是爲什麼當我認爲我已經將它加載到__index元表中時,該集被調用?那是我所做的還是別的什麼?

TIA

回答

4
int luaopen_testclass (lua_State *L) { 
    luaL_newmetatable(L, "LuaBook.testclass"); //leaves new metatable on the stack 
    lua_pushvalue(L, -1); // there are two 'copies' of the metatable on the stack 
    lua_setfield(L, -2, "__index"); // pop one of those copies and assign it to 
            // __index field od the 1st metatable 
    luaL_register(L, NULL, arraylib_m); // register functions in the metatable 
    luaL_register(L, "testclass", arraylib_f); 
    return 1; 
} 

該代碼相當於實例Lua代碼:

metatable = {} 
metatable.__index = metatable 
metatable.set = function() --[[ stuff --]] end 
metatable.get = function() --[[ stuff --]] end 

我假定 'new_testclass' C函數設置的元表 「LuaBook.testclass」 爲返回的表。

在您的代碼中,您不要將函數添加到metatable __index字段。您將指向metatable的指針分配給名爲__index的metatable字段,並向其註冊set和get函數。現在,如果將該元表達式設置爲從'new_testclass'函數返回的值(我假設你這麼做) - 讓我們調用該值'foo',並且調用foo:set(10),而不是Lua:

  1. 檢查,有沒有這樣的字段作爲「富」
  2. 看到的是「富」的元表
  3. 着眼於元表的__index場「設置」 - 看到這是一個表
  4. 檢查那個分配給__index字段的表有一個字段'set',它的值是一個函數
  5. 所稱的「集」的方法傳遞「富」自我參數

我希望這將幫助你找出什麼怎麼回事。

1

如果我理解你的問題,你問的是如何通過__index metamethod調用set()get()

的代碼可以在純LUA來表示:

local o = {} 

function o.get(self) 
    return self.ivalue 
end 

function o.set(self, val) 
    self.ivalue = val 
end 

a = {} 
mt = { 
    __index = function(t, n) 
     return o[n] 
    end 
} 

setmetatable(a, mt) 

print(a:get()) 
a:set(10) 
print(a:get()) 

結果:

nil 
10 

在這個例子中mt表被設置爲a表的元表。對getset都調用__index元方法,因爲a中目前不存在getset

如果此示例而不是改變爲這樣:

local o = {} 

function o.get(self) 
    return self.ivalue 
end 

function o.set(self, val) 
    self.ivalue = val 
end 

a = {} 

function a.get(self) 
    print('here') 
    return self.ivalue 
end 

mt = { 
    __index = function(t, n) 
     return o[n] 
    end 
} 

setmetatable(a, mt) 

print(a:get()) 
a:set(10) 
print(a:get()) 

結果:

here 
nil 
here 
10 

在這種情況下__index元方法是由於get指數在已經存在NOT調用爲get()a表。

一旦你明白它們是如何工作的,就可以使用metamethods創建許多有趣的構造。我建議閱讀13.4.1 - The __index Metamethod in PiL,並通過其他幾個例子。以上所有內容也可以從c api完成。