1. 關于 (…) 操作符
編譯階段優化:
Lua 編譯器會對常量字符串進行優化處理,將連續的字符串拼接操作 (…)
合并為單個字符串。這種優化僅適用于編譯期確定的常量字符串,不適用于運行時生成的動態字符串。 示例:
local str = "Hello" .. " " .. "World".."!!"
print(str) -- 編譯時等價于:local str = "Hello World"
--這段代碼運行后只會產生一個字符,(..)拼接過程中不會產生臨時字符串
運行時拼接:
當拼接操作涉及變量或動態值時,優化不會生效,拼接將在運行時執行。對于頻繁的字符串拼接操作,建議使用 table.concat
以避免創建大量臨時字符串導致的性能問題。 示例:
local a = "Hello"
local b = "World"
local c = "!!"
local str = a .. " " .. b.." "..c -- 運行時執行拼接
print(str)
2. 關于 table.concat
table.concat 要求數組元素必須是字符串或數字類型。數字會自動轉換為字符串,其他類型(如 boolean、table 或
nil)會引發錯誤。
3. 關于 xLua 調用 C# 重載方法
數字類型匹配:
Lua 僅使用 number 類型表示數字,而 C#包含多種數值類型(int、float、double、long)。當調用重載方法時,xLua 會按方法定義順序依次匹配參數類型。 需要注意的是int,float,double,long都屬于number 所以即使傳遞的是1.1這種浮點型,但是c#中仍然會調到第一個匹配以上四個參數的函數。
示例:比如如下代碼.lua調用會走到第一個也就是int型的重載函數中
//Main.cs
public class Main{static int c1, c2, c3, c4, c5,c6,c7;public static void Execute(int a){c1++;}public static void Execute(float a){c2++;}
}
--text.lua
CS.Main.Execute(1.1)
nil 類型
Lua 傳 nil 會被c#轉換為 null,這種情況下,對于引用類型參數的傳遞null,仍可以正常調用,匹配規則仍然是按照重載定義的順序。
lua傳遞參數個數多于#方法參數個數
傳遞參數多余c#方法的參數上限會報錯。
// C# 重載方法
public class MethodOverloading : MonoBehaviour
{public void Method(float num1){Debug.Log("Method(float num1)");}public void Method(int num1){Debug.Log("Method(int num1)");}public void Method(string num1){Debug.Log("Method(string num1)");}
}
local classObject = CS.MethodOverloading()
classObject:Method(10) -- 輸出結果取決于方法定義順序
注:修改方法定義順序將影響最終的調用結果。
下面是關于Xlua的luaCallc#調用反射源碼(非warp方式調用):
//xlua匹配函數代碼:
public int Call(RealStatePtr L)
{try{//若僅存在一個重載方法,且該方法無默認參數且無需強制類型檢查,則直接調用該重載。if (overloads.Count == 1 && !overloads[0].HasDefalutValue && !forceCheck) return overloads[0].Call(L);for (int i = 0; i < overloads.Count; ++i) //順序遍歷所有重載{var overload = overloads[i];if (overload.Check(L))//檢查參數是否匹配當前重載{return overload.Call(L);}}return LuaAPI.luaL_error(L, "invalid arguments to " + methodName);}catch (System.Reflection.TargetInvocationException e){return LuaAPI.luaL_error(L, "c# exception:" + e.InnerException.Message + ",stack:" + e.InnerException.StackTrace);}catch (System.Exception e){return LuaAPI.luaL_error(L, "c# exception:" + e.Message + ",stack:" + e.StackTrace);}}
//xlua檢查函數參數是否匹配代碼:
public bool Check(RealStatePtr L)
{int luaTop = LuaAPI.lua_gettop(L); // 獲取 Lua 棧頂索引(參數總數)int luaStackPos = luaStackPosStart; // 從指定起始位置開始檢查參數for (int i = 0; i < checkArray.Length; i++) // 遍歷預定義的檢查函數數組{// 1. 跳過最后一個參數(若為可變參數)if ((i == (checkArray.Length - 1)) && (paramsType != null))break;// 2. 檢查參數缺失(非可選參數)if (luaStackPos > luaTop && !isOptionalArray[i])return false; // 參數不足 → 檢查失敗// 3. 檢查參數類型不匹配else if (luaStackPos <= luaTop && !checkArray[i](L, luaStackPos))return false; // 類型不匹配 → 檢查失敗// 4. 移動棧指針(僅當參數存在或非可選時)if (luaStackPos <= luaTop || !isOptionalArray[i])luaStackPos++; // 指向下一個參數}// 5. 處理可變參數(params)情況return paramsType != null ? (luaStackPos < luaTop + 1 ? checkArray[checkArray.Length - 1](L, luaStackPos) : true) : luaStackPos == luaTop + 1;}
4. 關于table的rehash時機
我們都知道table是有數組和哈希兩部分組成,但是實際上數組部分和哈希部分都是使用數組數據結構實現的,也就是意味著他們的,只不過table的數組部分的數組存儲的是tValue,而哈希部分存儲的是一個Node節點。并且table初始化時如果沒有指定數組的長度,那么數值和哈希部分的長度都是0。那么后續增加數據的時候當如果儲存不下的時候就會觸發擴容-rehash。并且rehash都是按照2的指數增長。
local a = {}
for k = 1,5 dotable.insert(a,k,k)
end
-- 以上代碼執行后會觸發四次rehash,分別時添加1,2,3,5的時候
5.關于lua中面向對象
lua中繼承類的實例之間共享基類的靜態屬性。并且修改會實時同步所有實例。比如下段代碼中的A的M變量,所有繼承A的類的實例之間該屬性是共享的。
---@class A
---@field M _A
local A = class("A")
A.M = {A = 1,B = true}
lua中同一個類的所有實例的方法是共享的,在 Lua 的面向對象實現中,T1 和 T2 作為 B
類的實例,?共享類的方法,但各自擁有獨立的成員變量。這種設計是 Lua 面向對象編程的核心機制,其原理基于 ?元表(Metatable)??和 ?**__index 元方法**。比如:下列代碼的e是結果是true
---@class B:A
local B = class("B",A)function B:Execute()self.super.Execute(self)
endlocal T1 = B.new()
local T2 = B.new()
local e = T1.Execute==T2.Execute