Из https://www.lua.org/manual/5.3/manual.html см. раздел 2.4. Относительно операции метаметода __newindex приводит следующую цитату:

__newindex: Таблица присвоения индексации [ключ] = значение. Как и событие index, это событие происходит, когда таблица не является таблицей или когда ключ отсутствует в таблице. Метаметод ищется в таблице.

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

Когда есть метаметод __newindex, Lua не выполняет примитивное присваивание. (При необходимости сам метаметод может вызвать rawset для выполнения назначения.)

Об этом я спрашиваю, что конкретно намеревается сказать следующее

«Lua не выполняет примитивное присваивание (при необходимости сам метаметод может вызвать rawset для выполнения присваивания)».

Означает ли это, что если значение является числом, которое является примитивом, оно не будет присвоено предоставленной таблице через событие метаметода, и мы должны использовать rawget или что-то в этом роде? Это меня очень сбивает с толку и противоречит.

1
Grey 29 Янв 2021 в 04:45

1 ответ

Лучший ответ

Я хочу показать те же примеры, чтобы помочь вам разобраться в этой путанице. Пример примитивного присваивания:

local test = {}
test['x'] = 1 -- equal to rawset(test, 'x', 1)
print(test['x']) -- 1
print(rawget(test,'x')) -- 1

Код примитивного присваивания test['x'] = 1 равен rawset(test, 'x', 1), когда таблица test не имеет метаметода __newindex.

Затем пример метаметода __newindex:

local test = {}
setmetatable(test, {__newindex = function(t,key,value) end})
test['x'] = 1
print(test['x']) -- nil
print(rawget(test,'x')) -- nil

Назначение test['x'] = 1 инициирует вызов функции __newindex. если __newindex ничего не делает, то ничего не происходит, мы получим нулевой результат test['x'].

Если вызов функции __newindex rawset:

local test = {}
setmetatable(test, {
  __newindex = function(t,key,value) 
                 rawset(t,key,value) -- t:test key:'x' value:1
               end})
test['x'] = 1
print(test['x']) -- 1
print(rawget(test,'x')) -- 1

Код имеет тот же эффект, что и первый пример. Итак, в руководстве говорится:

«Lua не выполняет примитивное присваивание (при необходимости сам метаметод может вызвать rawset для выполнения присваивания)».

Тогда проблема в том, как мы можем использовать __newindex? Его можно использовать для разделения старого и нового индекса в таблице.

local test = {y = 1}
local newtest = {}
setmetatable(test, {
    __newindex = 
        function(t,key,value)
            newtest[key] = value
        end,
    __index = newtest
})

test["x"] = 1

print(test['x']) -- 1
print(test['y']) -- 1

print(rawget(test, 'x')) -- nil
print(rawget(test, 'y')) -- 1

К старому индексу 'x' и новому индексу 'y' может получить доступ test[key], и они могут быть разделены rawget(test, key)

2
Renshaw 5 Мар 2021 в 02:18