Есть ли что-то вроде указателей в Lua? - PullRequest
7 голосов
/ 08 декабря 2011

Я новичок в 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 ]

10 голосов
/ 08 декабря 2011

но значение будет сохранено в виде строки, поэтому на эту строку необходимо ссылаться в обоих местах, а не в таблице.

Во-первых, все типы (кроме логических значений, чисел илегкие пользовательские данные) являются ссылками - если t является таблицей, а вы делаете t2 = t, то и t, и t2 являются ссылками на одну и ту же таблицу в памяти.в Луа.Это означает, что все равные строки, такие как "abc" и результат "ab".."c", на самом деле являются одной строкой.Lua также хранит только ссылки на строки.Так что вам не стоит беспокоиться о памяти - в каждый момент времени существует только один экземпляр строки.

Вы можете безопасно сделать parent.child.value = parent.child[1].value, вы будете использовать память только для одного слота в таблице (несколькобайт), ни одна строка не будет скопирована, только ссылки.

3 голосов
/ 08 декабря 2011

Это хорошее приложение для использования метатаблиц:

parent={
    child={
        {value="whatever"},
        {value="blah"}
    }
}
setmetatable(parent.child,{__index=parent.child[1]})

Если индекс не найден в дочерней таблице (например, «значение»), он будет найден в таблице со значением __index.метатаблицы (первый элемент child в этом случае).

Теперь существует проблема с приведенным выше кодом, который мы можем видеть следующим образом:

print(parent.child.value) -- prints whatever
parent.child[1]=nil --remove first child
print(parent.child.value) -- still prints whatever!

Это потому, что метатабельныйсохраняет ссылку на первую дочернюю таблицу, предотвращая ее получение.Обходной путь для такого рода вещей: 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.

Если вы действительно заинтересованычтобы прочитать метатаблицы, попробуйте прочитать Программирование на Lua, глава 13 и глава 17 (слабые таблицы) . Lua-Users wiki на MetaMethods также может быть интересным.

3 голосов
/ 08 декабря 2011

Lua таблицы (часто используемые как объекты) не копируются, а имеют ссылки.(внутри них используется указатель)

0 голосов
/ 11 января 2014

С массивами C parent.child и parent.child[0] эквивалентны из-за арифметики указателя.Вы действительно не должны пытаться эмулировать одну из наиболее подверженных ошибкам, сбивающих с толку и избыточных возможностей C только потому, что вам нравится стиль.

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