Lua中的點、冒號與self,它們之間的關系主要體現在函數的定義與調用上,Lua在函數定義時可以用點也可以用冒號,如:
1 function mytable.fun(p) 2 return p 3 end 4 5 function mytable:fun(p) 6 return p 7 end
用冒號定義的函數有個特別的地方是它內部有個self表示自身可以直接訪問(雖然self並不是Lua的關鍵字,他它確實是可以訪問的),如同C++、C#的this:
1 myclass = {age = 10, name="aa"} 2 3 function myclass:fun(p) 4 print(self) 5 print(self.age) 6 print(p) 7 end 8 9 myclass:fun("22")
輸出:
table: 00D69810 10 22
可見self即myclass本身。如果上面不是冒號而是點則self不可用的會報錯,因為self是個nil值。
點定義的函數可以以冒號的形式調用,冒號定義的函數也可以用點的形式來調用,兩種方式都能成功調用到同一函數,但調用結果可能是錯誤的,上面代碼最后一行的冒號改為點來調用:
myclass.fun("22")
輸出:
22 nil nil
此時self不再是自身而是傳入的參數“22”,而本身需要的參數p卻是nil的。可見如果冒號定義的函數如果用點來調用時需要傳入的參數個數自動增加一個,函數內部若有用到self則self表示的便是函數傳入的第一個參數,第一個參數必須傳入本身,否則最后函數執行結果會是錯誤的。上例正確的點調用應該是:
myclass.fun(myclass, "22")
輸出:
table: 00F298B0 10 22
我們反過來試一下,先來看:
1 function myclass.fun(p1, p2) 2 print(p1) 3 print(p2) 4 end 5 6 myclass.fun("22","33")
輸出:
22 33
這個很顯然,如果調用改為冒號:
myclass:fun("22","33")
輸出:
table: 00E39A90 22
第一個參數p1不是“22”卻是一個table,第二個參數p2才是我們傳入的第一個數“22”,可見冒號調用以點定義的函數時,函數的參數的意義發生了變化,第一個參數強制變為了表示自身的變量(此時的p1等同於self),如果函數原來的參數一的意義要求不是要調用者將本身調用傳入則函數執行出錯,因此這種情況下的點定義的函數並不能用冒號來調用,雖然也能調用到該函數但結果卻是錯的。
綜上:
冒號定義成員函數相比點定義可以減少一個需要傳入自身的參數,內部用self來訪問自身;
點調用冒號定義的函數時,需要多傳入一個參數,傳入的第二個參數開始才對應於原函數的參數列表,函數內部用到的self則變為對應於傳入的第一個參數的普通變量,故傳入的第一個參數應該當是調用者自身(當然如果函數內部並沒有用到self則第一個參數隨便傳個什么都行);
冒號調用點定義的函數時,原函數的第一個參數強制變為等同於self的變量,傳入的參數從原參數的第二個參數開始才能一一對應上,因此通常這樣調用都是會出錯的(除非函數內部原本就把第一個參數在當self用...)。
故在Lua中成員函數的定義應該約定一種形式而不要點和冒號同時使用,不然調用者可能會不清楚該函數是否支持另一種方式的調用而增加出錯的可能。