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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM