Lua / c ++ проблема обработки именованных записей массива - PullRequest
0 голосов
/ 04 июня 2009

Я пытаюсь написать несколько классов C ++ для взаимодействия с LUA, и меня смущает следующее:

В следующем примере: Wherigo.ZCommand возвращает объекты «Command», также zcharacterFisherman.Commands - это массив объектов Command:

С помощью следующего кода LUA я понимаю его, и он работает правильно (luaL_getn возвращает 3 в zcharacterFisherman.Commands c ++ set newindex function):

zcharacterFisherman.Commands = {
  Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}

Но когда массив определен с помощью следующего кода LUA с немного другим синтаксисом, luaL_getn возвращает 0.

zcharacterFisherman.Commands = {
  Talk = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Talk2 = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Talk3 = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}

Все объекты определены в c ++, а объекты c ++ содержат все члены объекта, поэтому я пытаюсь просто подключить LUA к этим объектам c ++. Этого достаточно или мне нужно опубликовать часть моего кода ??

Ответы [ 3 ]

4 голосов
/ 05 июня 2009

Луа правильный.

Ваш первый пример формирует таблицу, которая содержит ровно три записи с индексами 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() для расширения таблиц.

2 голосов
/ 04 июня 2009

luaL_getn - для получения наибольшего числового элемента из массива в Lua. Массив - это таблица только с целочисленными индексами. Когда вы определяете таблицу в Lua (первый пример) без явной установки индексов, вы получите массив с элементами 1, 2 и 3. Естественно, luaL_getn возвращает здесь 3. luaL_getn НЕ определено для возврата количества элементов в таблице, оно определено для возврата наивысшего числового индекса в таблице (см. http://www.lua.org/manual/5.1/manual.html#pdf-table.maxn)

Во втором примере НЕ используются числовые индексы, и эта таблица не является массивом Lua - она ​​больше похожа на хеш-таблицу. Поскольку luaL_getn работает только с настоящими массивами, вы не ожидаете, что он будет работать здесь.

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

  1. Всегда использовать обозначение массива. Никогда не используйте что-либо еще в качестве ключей в вашей таблице. Таким образом вы получите много ускорений.
  2. Итерация по вашей таблице и подсчет количества элементов, когда вы хотите узнать размер таблицы. Язык не предоставляет однострочный метод для получения размера полной таблицы, поскольку общие таблицы реализованы с использованием хэшей и не отслеживают количество их элементов.
1 голос
/ 04 июня 2009

Lua таблицы объединяют как хеш-таблицы, так и стандартные массивы.

Ваш первый пример эквивалентен:

zcharacterFisherman.Commands = {
  [1] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [2] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [3] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}

getn поможет вам найти пустую числовую запись. Если t [1] == nil, то вполне вероятно, что table.getn (t) == 0. Во втором примере вы не назначаете zcharacterFisherman.Commands [1], поэтому вы получаете 0.

zcharacterFisherman.Commands = {
  [1] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [2] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [3] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}
zcharacterFisherman.Commands[1]=nil
print(table.getn(zcharacterFisherman.Commands))

Этот код напечатает 0 (или, возможно, число> = 3)

Как правило, нет способа напрямую получить количество элементов в хеш-таблице части без итерации по ним (например, с pair ())

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...