XLua 遍历C# List或Dictionary元素以及pairs和ipairs
https://blog.csdn.net/wangjiangrong/article/details/80238429
这一篇主要讲讲如何在lua中遍历List<>或者Dictionary<>的对象。
起因是在XLua官方讨论群里面正好有人问了怎么遍历,然后官方人员说使用for k,v in pairs(要遍历对象) do ... end就可以了。自己就顺手去试了试,结果发现一直报错,纠结了大半天,就在这儿记录一下。最后问了官方的人,结果是因为XLua不是最新的版本,心里苦啊。所有大家一定要更新好XLua,否则可能和我一样会遇到下面这些错误:
bad argument #1 to 'for iterator' (table expected, got System.Collections.Generic.List`1
遍历
需求
接着就说说如何实现XLua中遍历C#的List或Dictionary,首先我们先定义好需要遍历的测试对象,如下。
public class Fu {
public List<int> GetList() {
List<int> l = new List<int>();
l.Add(1);
l.Add(3);
l.Add(7);
l.Add(6);
l.Add(0);
return l;
}
public List<string> GetSList() {
List<string> l = new List<string>();
l.Add("aa");
l.Add("sdf");
l.Add("wer");
l.Add("rr");
l.Add("w3");
return l;
}
public Dictionary<int, string> GetDic() {
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(100, "ad");
dic.Add(103, "ewq");
dic.Add(140, "2s");
dic.Add(600, "fs");
return dic;
}
}
方法一
接着我们即可在Lua中实现对应的遍历,方法都是一样的(for k,v in pairs(list) do then),如下:
--获取对应的List
local fu = CS.Fu();
local list = fu:GetList();
local slist = fu:GetSList();
local dic = fu:GetDic();
--遍历
for k,v in pairs(list) do
print('List<int>---'..k..'--'..v);
end
print('============================');
for k,v in pairs(slist) do
print('List<string>---'..k..'--'..v);
end
print('============================');
for k,v in pairs(dic) do
print('Dictionary<int, string>---'..k..'--'..v);
end
打印的Log如下
方法二
当然除了上述的方法(类似c#的foreach)我们还可以用下面的方法来遍历(类似c#的for):
for i = 0, 4 do
print(list[i]);
end
方法三
如果XLua版本不升级的也可以在C#端给List,Dictionary做一层封装,将其转换成LuaTable,然后再用第一种方法去遍历。
补充
关于Lua中的for循环以及上诉用到pairs方法,在官方文档都有描述,这里贴一份(Lua5.3)
for
for 有两种形式:一种是数字形式,另一种是通用形式。
数字形式的 for 循环,通过一个数学运算不断地运行内部的代码块。 下面是它的语法:
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
block 将把 name 作循环变量。 从第一个 exp 开始起,直到第二个 exp 的值为止, 其步长为第三个 exp 。 更确切的说,一个for 循环看起来是这个样子
for v = e1, e2, e3 do block end
这等价于代码:
do
local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
if not (var and limit and step) then error() end
var = var - step
while true do
var = var + step
if (step >= 0 and var > limit) or (step < 0 and var < limit) then
break
end
local v = var
block
end
end
注意下面这几点:
1.所有三个控制表达式都只被运算一次, 表达式的计算在循环开始之前。 这些表达式的结果必须是数字。
2.var,limit,以及 step 都是一些不可见的变量。 这里给它们起的名字都仅仅用于解释方便。
3.如果第三个表达式(步长)没有给出,会把步长设为 1 。
4.你可以用 break 和 goto 来退出 for 循环。
5.循环变量 v 是一个循环内部的局部变量; 如果你需要在循环结束后使用这个值, 在退出循环前把它赋给另一个变量。
通用形式的 for 通过一个叫作 迭代器 的函数工作。 每次迭代,迭代器函数都会被调用以产生一个新的值, 当这个值为 nil 时,循环停止。 通用形式的 for 循环的语法如下:
stat ::= for namelist in explist do block end
namelist ::= Name {‘,’ Name}
这样的 for 语句
for var_1, ···, var_n in explist do block end
它等价于这样一段代码:
do
local f, s, var = explist
while true do
local var_1, ···, var_n = f(s, var)
if var_1 == nil then break end
var = var_1
block
end
end
注意以下几点:
1.explist 只会被计算一次。 它返回三个值, 一个 迭代器 函数, 一个 状态, 一个 迭代器的初始值。
2.f, s,与 var 都是不可见的变量。 这里给它们起的名字都只是为了解说方便。
3.你可以使用 break 来跳出 for 循环。
4.环变量 var_i 对于循环来说是一个局部变量; 你不可以在 for 循环结束后继续使用。 如果你需要保留这些值,那么就在循环跳出或结束前赋值到别的变量里去。
ipairs (t)
返回三个值(迭代函数、表 t 以及 0 ), 如此,以下代码
for i,v in ipairs(t) do body end
将迭代键值对(1,t[1]) ,(2,t[2]), ... ,直到第一个空值。
个人补充:使用这种方式遍历表,会从下标1开始读取对应的值(lua的table下标1起始),然后读取下标2,3...,当读到对应下标的值为nil时,就中断循环。同时忽略其他的下标,例如table['a']。
pairs (t)
如果 t 有元方法 __pairs, 以 t 为参数调用它,并返回其返回的前三个值。
否则,返回三个值:next 函数, 表 t,以及 nil。 因此以下代码
for k,v in pairs(t) do body end
能迭代表 t 中的所有键值对。
个人补充:这种方式遍历表,可以遍历表中所有的键值对。没有ipairs的那些约束,同时这种读取table并不是一种有序的读取。
因为纠结前面的问题的时候顺便也纠结了波pairs和ipairs的区别,注,上述遍历不能使用ipairs否则会报错
List<int>:LuaException: c# exception:System.ArgumentOutOfRangeException: Argument is out of range.
List<string>:LuaException: try to get System.Collections.Generic.List`1[System.String].Item throw a exception:System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Argument is out of range.
Dictionary:LuaException: try to get System.Collections.Generic.Dictionary`2[System.Int32,System.String].Item throw a exception:System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
关于两者的区分,直接例子说明(更多情况大家可以举例验证):
local table1 = {
5,6,8,4
}
for k,v in pairs(table1) do
print(k..'-'..v);
end
--打印结果为:1-5 2-6 3-8 4-4(有序)
print('============================');
for k,v in ipairs(table1) do
print(k..'-'..v);
end
--打印结果为:1-5 2-6 3-8 4-4(有序,因为下标1,2,3,4全有,所以全部输出)
local table2 = {
[1]=5,[3]=6,[4]=8,[5]=4
}
print('============================');
for k,v in pairs(table2) do
print(k..'-'..v);
end
--打印结果为:4-8 1-5 5-4 3-6(乱序)
print('============================');
for k,v in ipairs(table2) do
print(k..'-'..v);
end
--打印结果为:1-5(因为当读取下标2的值时为nil,中断循环)
local table3 = {
['a']=5,['b']=6,['c']=8,['d']=4
}
print('============================');
for k,v in pairs(table3) do
print(k..'-'..v);
end
--打印结果为:b-6 c-8 d-4 a-5(乱序)
print('============================');
for k,v in ipairs(table3) do
print(k..'-'..v);
end
--打印结果为:无打印(因为当读取下标1的值时为nil,中断循环)
————————————————
版权声明:本文为CSDN博主「王王王渣渣」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wangjiangrong/article/details/80238429