Lua: понимание части табличного массива и части хэша

В разделе 4, Таблицы, в Реализация Lua 5.0 есть и пример:
local t = {100, 200, 300, x = 9.3}

Итак, у нас есть t[4] == nil. Если я напишу t[0] = 0, это попадет в хэш-часть.
Если я напишу t[5] = 500, куда оно пойдет? Часть массива или часть хэша?
Я хотел бы услышать ответ для реализации Lua 5.1, Lua 5.2 и LuaJIT 2, если есть разница.


person happy_marmoset    schedule 10.07.2013    source источник
comment
Почему вы должны знать это? Это деталь реализации. Lua отлично справляется с разреженными массивами.   -  person lhf    schedule 10.07.2013


Ответы (2)


Непрерывные целые ключи, начинающиеся с 1, всегда идут в части массива.

Ключи, которые не являются положительными целыми числами, всегда идут в хеш-части.

Кроме того, он не указан, поэтому вы не можете предсказать, где t[5] будет храниться в соответствии со спецификацией (и он может или не может перемещаться между ними, например, если вы создаете, а затем удаляете t[4].)

LuaJIT 2 немного отличается — он также будет хранить t[0] в части массива.

Если вам нужно, чтобы это было предсказуемо (что, вероятно, является запахом дизайна), придерживайтесь чистых таблиц массивов (непрерывные целочисленные ключи, начинающиеся с 1 - если вы хотите оставить пробел, используйте значение false вместо nil) или чистые хеш-таблицы ( избегайте неотрицательных целочисленных ключей.)

person finnw    schedule 10.07.2013
comment
Указывая на функциональное различие в характеристиках таблиц, использование по умолчанию #t имеет смысл только в том случае, если положительные целые ключи остаются непрерывными. Как говорит @lhf, остальное - это детали реализации. - person Tom Blodget; 10.07.2013

Цитата из Реализация Lua 5.0

Часть массива пытается сохранить значения, соответствующие целочисленным ключам от 1 до некоторого предела n. Значения, соответствующие нецелочисленным ключам или целочисленным ключам за пределами диапазона массива, хранятся в хэш-части.

Индекс части массива начинается с 1, поэтому t[0] = 0 перейдет в хеш-часть.

Вычисленный размер части массива равен наибольшему n, такому что по крайней мере половина слотов между 1 и n используется (чтобы не тратить место на разреженные массивы) и есть по крайней мере один используемый слот между n/2+1 и n( чтобы избежать размера n, когда подойдет n/2).

Согласно этому правилу в таблице примера:

local t = {100, 200, 300, x = 9.3}

Часть массива, которая содержит 3 элемента, может иметь размер 3, 4 или 5. (EDIT: размер должен быть 4, см. комментарий @dualed.)

Предположим, что массив имеет размер 4, при записи t[5] = 500 часть массива больше не может содержать элемент t[5], что, если размер части массива изменится до 8? При размере 8 часть массива содержит 4 элемента, что равно (значит, не меньше) половине размера массива. И индекс между n/2+1 и n, который в данном случае равен от 5 до 8, имеет один элемент: t[5]. Таким образом, размер массива 8 может выполнить требование. В этом случае t[5] перейдет в часть массива.

person Yu Hao    schedule 10.07.2013
comment
Это не может быть размер 3 или 5, так как часть массива имеет размер 2^m, согласно lua.org/gems/sample.pdf страница 19, так что будет 4 - person dualed; 11.07.2013
comment
@dualed Спасибо, я так и думал, но у меня не было доказательств. - person Yu Hao; 11.07.2013