XLua 遍历C# List或Dictionary元素以及pairs和ipairs

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

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值