Lua中ipairs和pairs的区别

泛型for

首先是泛型for的语法

for var-list in exp-list do 
	body 
end

当执行for循环时候,泛型for会接收exp-list返回的三个值分别用作迭代函数、不可变状态和控制变量的初始值。上述步骤完成后泛型for使用不可变状态和控制变量为参数来调用迭代函数,泛型for将迭代函数的返回值赋给变量列表中声明的变量,如果第一个返回值(赋给控制变量的值)为 nil ,那么循环终止;否则,泛型for执行它的循环体并再次调用迭代函数,再不断地重复这个过程。
伪代码是这样的:

local _f, _s, _var = exp-list 
while true do 
	local var_1, ... , var_n = _f(_s, _var)
	_var = var_1 
	if _var == nil then break end 
	block 
end

而ipairs和pairs是lua提供的两个迭代函数生成器也就是前面的exp-list

ipairs的实现

/*
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
  lua_Integer i = luaL_checkinteger(L, 2);
  // i = i + 1
  i = luaL_intop(+, i, 1);
  lua_pushinteger(L, i);
  // table[i] == nil and return 1 or return 2
  return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}

/*
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
  luaL_checkany(L, 1);
  lua_pushcfunction(L, ipairsaux);  /* iteration function */
  lua_pushvalue(L, 1);  /* state */
  lua_pushinteger(L, 0);  /* initial value */
  return 3;
}

当我们使用ipairs的时候会调用luaB_ipairs,可以看到ipairs执行之后会返回三个参数,第一个参数是个遍历函数ipairsaux,第二个是ipairs函数调用时候传入的table,第三个参数是0。ipairs的遍历函数是通过 i 作为table的key,不断自增 i 从而达到遍历的效果的。

可以理解为如下代码:

local iter = function(t, i)
    i = i + 1
    local v = t[i]
    if v then
        return i, v
    end
end

function ipairs(t)
    return iter, t, 0
end

pairs的实现

static int luaB_next (lua_State *L) {
  luaL_checktype(L, 1, LUA_TTABLE);
  lua_settop(L, 2);  /* create a 2nd argument if there isn't one */
  if (lua_next(L, 1))
    return 2;
  else {
    lua_pushnil(L);
    return 1;
  }
}

static int pairscont (lua_State *L, int status, lua_KContext k) {
  (void)L; (void)status; (void)k;  /* unused */
  return 3;
}

static int luaB_pairs (lua_State *L) {
  luaL_checkany(L, 1);
  if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) {  /* no metamethod? */
    lua_pushcfunction(L, luaB_next);  /* will return generator, */
    lua_pushvalue(L, 1);  /* state, */
    lua_pushnil(L);  /* and initial value */
  }
  else {
    lua_pushvalue(L, 1);  /* argument 'self' to metamethod */
    lua_callk(L, 1, 3, 0, pairscont);  /* get 3 values from metamethod */
  }
  return 3;
}

当我们使用pairs的时候会调用luaB_pairs,在没有__pairs元方法的时候,可以看到pairs执行之后返回三个参数,第一个参数是个遍历函数luaB_next,第二个是pairs函数调用时候传入的table,第三个参数是nil。这里的luaB_pairs使用的就是遍历函数lua_next就是我们常用的next函数,也就是说pairs是通过不断调用next函数达到遍历的效果的。

可以理解为如下代码:

function pairs(t)
    return next, t, nil
end

两者区别

由他们的实现可以看出两者的区别
ipairs是没法保证完整遍历的,优势是可以有序遍历。
pairs是由于next的机制可以保证完整的遍历,但是却没办法保证顺序。

-- 遇table1[3]==nil时终止 ipairs可遍历到:a, b   pairs可遍历到:a, b, d
local table1 = { "a", "b", nil, "d" } 
 -- ipairs可遍历到:a, b, d    pairs可遍历到:a, b, d
local table2 = { "a", "b", c = 1, "d" } 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值