Lua __newindex



1.查詢與更新

上一篇文章我們介紹了__index元方法,總結來說,__index元方法是用於處理調用table中不存在的字段。

注意,【調用】這個詞,只是調用,而不是賦值。

 

如果,我們要對table中某個不存在的字段賦值呢?(小若:就,直接賦值啊!)

沒錯,我們直接就能賦值了,不會報錯的。

問題是,如果我想監控這個操作呢?如果有人想對table不存在的字段進行賦值的時候,我想進行一些額外的處理呢?

這時候就要用到__newindex。

 

大家要記住這句話:__index用於查詢,__newindex用於更新。

等會不要混亂了, 初次接觸的話,有可能會混亂。

 

2.看看普通的賦值情況

我們先來看看正常情況下的賦值,如代碼:

  1.     local smartMan = {
  2.         name = "none",
  3.         money = 9000000,
  4.        
  5.         sayHello = function()
  6.             print("大家好,我是聰明的豪。");
  7.         end
  8.     }
  9.    
  10.     local t1 = {};
  11.    
  12.     local mt = {
  13.         __index = smartMan,
  14.     }
  15.    
  16.     setmetatable(t1, mt);
  17.    
  18.     t1.sayHello = function()
  19.         print("en");
  20.     end;
  21.    
  22.     t1.sayHello();

這是上一篇用過的例子,一個模仿繼承結構的例子。

來分析一下,mt作爲t1的元表,設置__index爲smartMan。

於是,當我們調用t1中不存在的字段時,就會自動去smartMan中查找。

比如我們調用了t1.sayHello(),自然能找到對應的函數。

 

先來看看輸出結果:

[LUA-print] en

我們調用t1的sayHello字段,t1並不存在這個字段(雖然可以通過__index的方式來找到smartMan的sayHello字段)。

但這不影響,給這個字段賦值,然後再調用t1.sayHello(),發現是成功的。

這和我們以往的做法一樣,對table做正常的賦值操作,不管table本身是否存在這個字段。

 

3.監控賦值

好了,普通情況我們已經試過了,如果我們想監控table的賦值操作呢?

對於不存在的字段,我們不需要被賦值呢?想要製作一個只讀的table呢?

 

如果你有這些想法,那麼歡迎撥打屏幕下方的號碼,前10位打進的還贈送價值..(小若:停!)

那麼,如果你有這些想法,請看看下面的代碼:

  1.     local smartMan = {
  2.         name = "none",
  3.         money = 9000000,
  4.        
  5.         sayHello = function()
  6.             print("大家好,我是聰明的豪。");
  7.         end
  8.     }
  9.    
  10.     local t1 = {};
  11.    
  12.     local mt = {
  13.         __index = smartMan,
  14.         __newindex = function(table, key, value)
  15.             print(key .. "字段是不存在的,不要試圖給它賦值!");
  16.         end
  17.     }
  18.    
  19.     setmetatable(t1, mt);
  20.    
  21.     t1.sayHello = function()
  22.         print("en");
  23.     end;
  24.     t1.sayHello();

留意mt元表,我們給它加了一個__newindex。

運行代碼,輸出結果如下:

[LUA-print] sayHello字段是不存在的,不要試圖給它賦值!
[LUA-print] 大家好,我是聰明的豪。

很顯然,sayHello字段賦值失敗,因爲給sayHello字段賦值的時候,調用了__newindex元方法,代替了賦值操作。

(小若:爲什麼?sayHello字段不是存在的麼?爲什麼會說不存在呢?)

 

這裏有一個地方要注意的,t1中確實是不存在sayHello字段的,它只是因爲有元表存在,而元表裏的__index元方法的值是smartMan這個table。

從而,可以在t1找不到sayHello字段的時候,去smartMan中尋找。

但,實際上,t1確實是不存在sayHello字段的,不知道大家能繞明白不?

 

因此,當試圖給t1的sayHello字段賦值時,Lua判定sayHello字段是不存在的,所以會去調用元表裏的__newindex元方法。

__newindex元方法被調用的時候會傳入3個參數:table本身、字段名、想要賦予的值。

 

4.隔山打牛,通過給一個table給另一個table的字段賦值

和__index一樣,__newindex元方法也可以賦予一個table值。

這種情況下就有點意思了,先看看代碼:

  1.     local smartMan = {
  2.         name = "none",
  3.     }
  4.    
  5.     local other = {
  6.         name = "大家好,我是很無辜的table"
  7.     }
  8.    
  9.     local t1 = {};
  10.    
  11.     local mt = {
  12.         __index = smartMan,
  13.         __newindex = other
  14.     }
  15.    
  16.     setmetatable(t1, mt);
  17.      
  18.     print("other的名字,賦值前:" .. other.name);
  19.     t1.name = "小偷";
  20.     print("other的名字,賦值後:" .. other.name);
  21.     print("t1的名字:" .. t1.name);

這次的代碼和剛剛差不多,但是我們新加了一個other的table,然後把other作爲__newindex的值。

於是,當給t1的name字段賦值時,就會發生一些奇怪的事情…

先來看看輸出結果:

[LUA-print] other的名字,賦值前:大家好,我是很無辜的table
[LUA-print] other的名字,賦值後:小偷
[LUA-print] t1的名字:none

當給t1的name字段賦值後,other的name字段反而被賦值了,而t1的name字段仍然沒有發生變化。

(實際上t1的name字段還是不存在的,它只是通過__index找到了smartMan的name字段,這個就不嘮叨了。)

於是,我們給t1的name賦值的時候,實際上是給other的name賦值了。

好吧,可憐的other。

 

5.總結規則

這就是__newindex的規則:

a.如果__newindex是一個函數,則在給table不存在的字段賦值時,會調用這個函數。

b.如果__newindex是一個table,則在給table不存在的字段賦值時,會直接給__newindex的table賦值。

 

6.結束

好了,關於元表和元方法的基礎內容基本上告一段落了,接下來還有一篇關於元表和元方法的文章,也是一些比較零散的知識點。

之後,還會提到元表和元方法的,因爲它們實在是太重要了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章