2014-07-17 45 views
3

當沒有鍵引用時,表有可能返回一個特定的值而不是自己的引用嗎?我可以重寫一個Lua表的返回值嗎?

比方說,我有如下表:

local person = { 
    name = "Kapulani", 
    level = 100, 
    age = 30, 
} 

在Lua中,我可以很容易地提及「person.name」,「person.level」,或「person.age」而獲得的值如預期。但是,在某些情況下,我可能只想引用「person」,而不是獲取「table:」,而是要返回「person.name」的值。

換句話說,我希望person.x(或person [x])從表中返回適當的條目,但沒有鍵的人可以返回person.name(或person [「name 「])。有沒有這種我無法找到的機制?

我對metatables沒有成功,因爲__index只適用於密鑰不存在的情況。如果我把「人」到一個單獨的表,我可以想出:

local true_person = { 
    ... -- as above 
} 

local env_mt = { 
    __index = function(t, k) 
     if k == 'person' then 
      return true_person 
     end 
    end 
} 

local env = setmetatable({}, env_mt) 

這讓我用__index做一些特殊處理,除了有我告訴沒有可辨別的方式,從__index()是否我得到env.person(我想要返回true_person.name)或env.person [key](我想要將true_person作爲表返回)的請求,以便'key'可以是適當訪問)。

有什麼想法?我可以用不同的方式來解決這個問題,但希望我可以按照這些方式來解決這個問題

+2

您正在與Lua的語法作鬥爭,以創建您自己的DSL。它真的提供任何優勢嗎?一個例子會有所幫助。無論如何,你可以嘗試__call metamethod或簡單地將一個:default()方法添加到所有這些表中,並使用通用或特定於表的實現。 –

+0

我絕對權衡利弊。我一直在玩** __電話**,儘管我希望避免使用**()**,但它與我所尋找的有點接近。我希望的優點是,通過限制現有語法和Lua語法之間的「翻譯」量,當Lua拋出錯誤時,輸出對用戶來說是相對有意義和可識別的。因此,將**&**轉換爲**和**以及** | **轉換爲**或**並不奇怪,但是在一些情況下將** **轉換爲** person()**當** person.name **不需要翻譯時,地方可能有點奇怪。 – Kapulani

回答

2

你可以做到這一點時,該表被設置__tostring元表項作爲一個字符串:

$ cat st.lua 
local person = { 
    name = "Kapulani", 
    level = 100, 
    age = 30, 
} 

print(person) 
print(person.name) 
print(person.age) 

setmetatable(person, {__tostring = function(t) return t.name end}) 
print(person) 

$ lua st.lua 
lua st.lua 
table: 0x1e8478e0 
Kapulani 
30 
Kapulani 
+0

這非常有幫助和直接。如果默認值不是字符串,而是數字呢? __tonumber似乎不是一個有效的metamethod。有沒有解決方法來使用數字值?也就是說,用年齡代替名字? – Kapulani

+2

@Kapulani這可以做到,但我會說這是一個強大的合同,__tostring應該返回一個字符串。 –

+1

metamethod名稱用於正在執行的操作(和功能)。你當然可以從metamethod中返回一個數字。正如@TomBlodget所說,這可能有點奇怪,但在大多數情況下,它不會傷害任何東西(普通字符串用例會立即自動將該數字自動轉換爲字符串)。唯一會受到傷害的是如果有人試圖使用字符串metamethod/etc。直接返回值。 –

1

我不知道,你問的是一個好主意,因爲它在飛面向組合性。通常人們會想到以下兩個程序做同樣的事情,但你想它們的理解不同

print(person.name) 

local p = person 
print(p.name) 

它也並不十分明確分配將如何工作。 person.age = 10應該改變年齡,但person = otherPerson應該改變對perrson的引用,而不是年齡。

如果你不關心組合性,並磺酰基讀取數據,然後解決問題更直接的方式是讓接收一個字符串編碼

query("person.age") -- 17 
query("person.name") -- "hugomg" 
query("person")  -- 17; query gets to default to whatever it wants. 

爲了保持字段的查詢功能語法更輕巧,你可以省略可選括號

q"person.age" 
q"person" 

或者你可以在全局表延長__index元方法,_G

setmetattable(_G, { __index = function(self, key) return query(key) end }) 

print (person_age) -- You will need to use "_" instead of "." for the 
         -- query to be a valid identifier. 
相關問題