Луа правильный.
Ваш первый пример формирует таблицу, которая содержит ровно три записи с индексами 1, 2 и 3, ни одна из которых не указана явно. В этом случае table.maxn()
, оператор #
и lua_objlen()
все согласны с тем, что существует три элемента массива.
Ваш второй пример формирует таблицу, которая содержит ровно три записи с индексами «Talk», «Talk2» и «Talk3», все они указаны явно, но ни одно из них не является целым числом. В этом случае table.maxn()
, оператор #
и lua_objlen()
все согласны с тем, что элементы массива равны нулю.
Почему это правильный ответ?
Lua table
- это ассоциативный массив, который может отображать значения любого типа (кроме nil
) на значения любого типа (опять же, кроме nil
). В Lua нет другого общего типа контейнера, поэтому таблицы используются практически для всего. Реализация не является частью спецификации Lua, но на практике таблица индексируется как хеш-таблица, и нет естественного упорядочения ключей.
Однако, общий вариант использования таблиц - это контейнер, который действует как обычный массив. Такой контейнер имеет смежные целочисленные индексы и может повторяться по порядку. Реализация таблицы делает это особенно эффективным для целочисленных ключей, начинающихся с 1
. Эти записи в таблице физически выделяются как непрерывный массив, а ключи не хэшируются и не хранятся. Это экономит место для хранения как при распределении ресурсов, так и за счет того, что некоторые ключи не хранятся вообще. Это также экономит время выполнения, поскольку доступ осуществляется путем прямого вычисления, а не путем вычисления хэша и проверки соответствующего значения.
Поскольку массивы - это просто таблицы, синтаксис инициализатора таблицы был разработан для того, чтобы сделать этот случай простым и понятным, а также для поддержки другого распространенного варианта использования, где ключи - это строки, которые оказываются действительными идентификаторами.
Луа 5,1 против Луа 5,0
В текущем выпуске Lua (5.1.4, но это верно для всех выпусков 5.1) функции Lua 5.0 table.getn()
, table.setn()
, luaL_getn()
и luaL_setn()
все устарели , как обычно используется поле таблицы n
для массива, чтобы указать его длину массива. Функция table.getn()
заменяется оператором #
, а luaL_getn()
на lua_objlen()
. Нет эквивалента функциям setn()
, поскольку Lua теперь управляет размером массива за кулисами.
Оператор #
определен в таблице для возврата целого числа, так что при индексировании таблицы по следующему большему целому числу возвращается nil
. Для пустого массива (например, a = {}
) он возвращает 0, потому что a[1] == nil
. Для обычного массива он возвращает самый большой используемый индекс. Однако, если в массиве есть дыры (отсутствующие элементы), он может вернуть индекс, предшествующий любой дыре, или последний использованный индекс. Если требуется фактическое использование наибольшего целочисленного индекса, можно использовать новую функцию table.maxn()
, но она должна перебирать все записи таблицы, чтобы найти это максимальное значение, и, следовательно, должна использоваться только тогда, когда #
не может.
Это приводит к общепринятой идиоме для добавления элементов в массив: a[#a+1] = "some new value"
. Этот идиом теперь часто рекомендуется вместо table.insert()
для расширения таблиц.