Есть ли что-нибудь вроде указателей в 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 только потому, что вам нравится стиль.