2009-11-04 3 views
9

я наткнулся на странное поведение в Lua функцию распаковкиLua unpack bug?

table1 = {true, nil, true, false, nil, true, nil} 
table2 = {true, false, nil, false, nil, true, nil} 

a1,b1,c1,d1,e1,f1,g1 = unpack(table1) 
print ("table1:",a1,b1,c1,d1,e1,f1,g1) 

a2,b2,c2,d2,e2,f2,g2 = unpack(table2) 
print ("table2:",a2,b2,c2,d2,e2,f2,g2) 

Выход:

table1: true nil true false nil nil nil 
table2: true false nil nil nil nil nil 

Второй распаковывать обеспечивает параметры до первого значения ноль. Я мог бы жить с этим. Первая таблица обеспечивает 4? параметры с одним, равным нулю в середине. Он имеет 4 параметра, которые не ноль, но они не показаны.

Может ли это объяснить это? Это пытались с codepad.org и Lua 5,1

ответ

12

Проблема может быть решена, просто указав начальные и конечные индексы для unpack() и использования table.maxn() в качестве конечного индекса:

 
table1 = {true, nil, true, false, nil, true, nil} 

a1,b1,c1,d1,e1,f1,g1 = unpack(table1, 1, table.maxn(table1)) 
print ("table1:",a1,b1,c1,d1,e1,f1,g1) 
-->table1: true nil  true false nil  true nil 

Истинная причина расхождения в том, как обрабатываются две таблицы, заключается в логике определения длины части массива таблицы.

Функция luaB_unpack() использует luaL_getn(), которая определена в терминах lua_objlen(), которая вызывает luaH_getn() для таблиц. luaH_getn() смотрит на последнюю позицию массива, и если он nil выполняет двоичный поиск границы в таблице («такой, что t [i] не равен нулю, а t [i + 1] равно nil»). Бинарный поиск конца массива является причиной того, что table1 обрабатывается иначе, чем table2.

Это должно быть проблемой только в том случае, если последняя запись в массиве nil.

От Programming in Lua (pg.16) (Вы должны купить эту книгу.): Когда массив имеет отверстие - ноль элементов внутри него - оператор длины может принимать любой из этих нильэлементов как конечный маркер.Поэтому вам следует избегать использования оператора длины на массивах, которые могут содержать дыры.

unpack() использует оператор длины lua_objlen(), который «может принимать любые из [n] элементов в качестве конца» массива.

+0

Спасибо, ты спас мой день. Означает ли это, что table.maxn() перемещает весь выделенный размер таблицы? – Geggamojja

+0

table.maxn() «Возвращает наибольший положительный числовой индекс данной таблицы» см. Http://www.lua.org/manual/5.1/manual.html#pdf-table.maxn – gwell

+0

is table.maxn действительно гарантированно верните правильное значение (= количество объектов в литературе таблицы) здесь? – u0b34a0f6ae

3

2.2 - Values and Types

[...] Тип таблица реализует ассоциативные массивы, то есть массивы, которые могут быть проиндексированы не только с номера, но с любым значением (кроме нуля). Таблицы могут быть гетерогенными; то есть они могут содержать значения всех типов (за исключением ноль). [...]

Учитывая nil к записи будут перерыва таблицы перечисление и ваши переменное обыкновению быть INIT правильно.

Вот простой пример, который демонстрирует поведение проблематичной:

table1 = {true, false, nil, false, nil, true, nil} 
for k,v in ipairs(table1) do 
    print(k, v) 
end 

выход:

1 true 
2 false 
>Exit code: 0 
+0

В частности, я подозреваю, что он игнорирует 'nil', который он указал. – RCIX

+0

Нет, это не RCIX, в этом случае таблица 2 также вернула бы 4 значения. – Geggamojja

+0

Единственная причина, по которой остановился цикл for, заключается в том, что итератор возвратил нуль в позиции 3. Таблица была по-прежнему инициализирована правильно, потому что 'assert (table1 [1] == true и table1 [2] == false и table1 [3] == nil и table1 [4] == false и table1 [5] == nil и table1 [6] == true и table1 [7] == nil) 'не утверждают. – gwell