zoukankan      html  css  js  c++  java
  • unpack的一点使用问题

    • 现象

    lua支持不定数量参数,通过...传送,使用unpack解开。看一段代码

     1 local function arg2(...)
     2     print('****************')
     3     print(unpack(arg))
     4     for k, v in pairs(arg) do
     5         print(k, v)
     6     end
     7     print(arg[1], arg[2], arg[3])
     8     print('++++++++++++++++')
     9 end
    10 arg2('a', nil, 'c')
    11 arg2(nil, 'b', 'c')
    12 arg2(nil, 'b', nil)

    其实我们预期传入三个参数,但是由于某种情况,有的参数值为nil,我们当然希望在unpack后还和传入的值一样。看一下执行结果

    我们发现,前面两个和预期一致,第三个unpack却没有得到内容,是个空串,但按下标逐个打印的时候内容仍然是存在的,这样势必会导致函数执行结果不能和传入的参数一致。

    • 解释

    unpack的说明如下,从指定的范围依次取出,如果不指定则从开始1到长度l,由求长度操作符#决定。

    上面的代码中没有给出i和j,使用默认处理。换为指定范围如下:

     1 local function arg2(...)
     2     print('****************')
     3     print(unpack(arg, 1, 3))
     4     for k, v in pairs(arg) do
     5         print(k, v)
     6     end
     7     print(arg[1], arg[2], arg[3])
     8     print('++++++++++++++++')
     9 end
    10 arg2('a', nil, 'c')
    11 arg2(nil, 'b', 'c')
    12 arg2(nil, 'b', nil)

    执行后如下

     这时候就和预期的一致了。不幸的是,我们并不总是知道这个长度的。而未指定时结果不对,猜想和#操作的结果有关,其文档说明是

    关键是后面补充的部分,如果第一个元素是nil,则长度为0;如果非nil值之间有了“洞”,则不确定长度了。

    • 代码

    下面是unpack的代码

     1 static int luaB_unpack (lua_State *L) {
     2   int i, e, n;
     3   luaL_checktype(L, 1, LUA_TTABLE);
     4   i = luaL_optint(L, 2, 1);
     5   e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
     6   n = e - i + 1;  /* number of elements */
     7   if (n <= 0) return 0;  /* empty range */
     8   luaL_checkstack(L, n, "table too big to unpack");
     9   for (; i<=e; i++)  /* push arg[i...e] */
    10     lua_rawgeti(L, 1, i);
    11   return n;
    12 }

     下面是求解#的过程

     1 static int unbound_search (Table *t, unsigned int j) {
     2   unsigned int i = j;  /* i is zero or a present index */
     3   j++;
     4   /* find `i' and `j' such that i is present and j is not */
     5   while (!ttisnil(luaH_getnum(t, j))) {
     6     i = j;
     7     j *= 2;
     8     if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */
     9       /* table was built with bad purposes: resort to linear search */
    10       i = 1;
    11       while (!ttisnil(luaH_getnum(t, i))) i++;
    12       return i - 1;
    13     }
    14   }
    15   /* now do a binary search between them */
    16   while (j - i > 1) {
    17     unsigned int m = (i+j)/2;
    18     if (ttisnil(luaH_getnum(t, m))) j = m;
    19     else i = m;
    20   }
    21   return i;
    22 }
    23 
    24 
    25 /*
    26 ** Try to find a boundary in table `t'. A `boundary' is an integer index
    27 ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
    28 */
    29 int luaH_getn (Table *t) {
    30   unsigned int j = t->sizearray;
    31   if (j > 0 && ttisnil(&t->array[j - 1])) {
    32     /* there is a boundary in the array part: (binary) search for it */
    33     unsigned int i = 0;
    34     while (j - i > 1) {
    35       unsigned int m = (i+j)/2;
    36       if (ttisnil(&t->array[m - 1])) j = m;
    37       else i = m;
    38     }
    39     return i;
    40   }
    41   /* else must find a boundary in hash part */
    42   else if (t->node == dummynode)  /* hash part is empty? */
    43     return j;  /* that is easy... */
    44   else return unbound_search(t, j);
    45 }
  • 相关阅读:
    Android用Application设置全局变量以及使用
    Android Spinner
    margin和padding的区别
    Java中Calendar常用方法封装
    Java中Calendar的用法以及获取当前日期的后一天
    Oracle Exists用法
    (Oracle)rownum用法详解
    Android中GestureDetector.OnGestureListener
    Java文件路径详解[转载]
    Android利用ViewFlipper实现屏幕切换动画效果
  • 原文地址:https://www.cnblogs.com/njucslzh/p/2872958.html
Copyright © 2011-2022 走看看