Есть ли что-нибудь вроде указателей в Lua?
Я новичок в Lua, и я хочу создать таблицу [doh], которая будет хранить такие значения, как:
parent.child[1].value = "whaterver"
parent.child[2].value = "blah"
однако чаще всего есть только один ребенок, поэтому было бы проще получить доступ к значению следующим образом:
parent.child.value
чтобы сделать вещи проще, я хотел бы сохранить мои ценности, таким образом, что
parent.child[1].value == parent.child.value
но для этого мне пришлось бы дважды это значение сохраняется в памяти. Есть ли способ сделать это, чтобы:
parent.child.value points to parent.child[1].value
без сохранения значение дважды в памяти?
дополнительный вопрос, Как проверить, сколько памяти занимает таблица?
4 ответов
но значение будет храниться как строка, поэтому это строка, которая должна ссылаться в обоих местах, а не в таблице.
во-первых, все типы (кроме булевых, чисел и легких userdata) являются ссылками-if t
таблица, а вы t2 = t
, тогда как t
и t2
- это ссылки на ту же таблицу в памяти.
вторая вещь-строка интернирована в Lua. Это означает, что все равные строки, как "abc"
и в результате "ab".."c"
на самом деле это одна строка. Lua также хранит только ссылки на строки. Поэтому вы не должны беспокоиться о памяти - существует только один экземпляр строки за раз.
вы можете безопасно сделать parent.child.value = parent.child[1].value
, вы будете использовать память только для одного слота в таблице (несколько байтов), никакая строка не будет скопирована, только ссылка.
таблицы Lua (часто используемые как объекты) не копируются, а ссылаются. (внутренне для них используется указатель)
Это хорошее приложение для использования metatables:
parent={
child={
{value="whatever"},
{value="blah"}
}
}
setmetatable(parent.child,{__index=parent.child[1]})
если индекс не найден в дочерней таблице (например, "value"), он просматривается в таблице, которая является значением __index metatable (первый элемент дочернего элемента в этом случае).
Теперь есть проблема с вышеуказанным кодом, который мы можем видеть как folows:
print(parent.child.value) -- prints whatever
parent.child[1]=nil --remove first child
print(parent.child.value) -- still prints whatever!
это потому, что metatable сохраняет ссылку на первую дочернюю таблицу, предотвращая ее от жатвы. Этот обходной путь для такого рода вещей-A) сделать метатабельную слабую таблицу или B) сделать поле __index функцией, вместо того, чтобы ссылаться на нее в таблице.
-- A)
setmetatable(parent.child, setmetatable(
{__index=parent.child[1]} -- metatable for the child table
{__mode='v'}-- metatable for the metatable, making it have weak keys
)
)
parent.child[1]=nil
print(parent.child.value) --returns nil
parent.child[1]={value='foo'}
print(parent.child.value) -- prints nil, the metatable references to a non-existant table.
-- hence solution B)
setmetatable(parent.child, {__index=function(t,k) return parent.child[1][k]})
print(parent.child.value) -- 'whatever'
parent.child[1]=nil
print(parent.child.value) -- nil
parent.child[1]={value='foobar'
print(parent.child.value) -- foobar, now it will always refer to the table at child[1], even when it changes.
Если вам действительно интересно читать о metatables, попробуйте прочитать программирование в Lua, Глава 13 и Глава 17 (слабые столы). Lua - пользователи wiki на Метаметодах также может быть интересно.
с массивами C,parent.child
и parent.child[0]
эквивалентны из-за арифметики указателей. Вы действительно не должны пытаться эмулировать одну из самых подверженных ошибкам, запутанных и избыточных функций C только потому, что вам нравится стиль.