В версии функции ООП self:deepcopy(something)
с синтаксисом метода (двоеточие) не выполняет то, что вам нужно.Это эквивалентно self.deepcopy(self, something)
;второй аргумент something
игнорируется, и вы просто пытаетесь повторно копировать один и тот же self
снова и снова, пока не возникнет переполнение стека.Вы должны сделать self.deepcopy(something)
с точкой, чтобы передать something
в качестве аргумента self
(копируемый аргумент).
Вызов self.deepcopy
внутри определения метода deepcopy
предполагает, чтоу каждой подтаблицы есть функция self.deepcopy
.Если нет, вы получите ошибку «попытка вызвать нулевое значение».Но вы можете сделать это, если хотите, чтобы у каждой подтаблицы была своя собственная версия deepcopy
, которая используется при копировании непосредственных потомков этой таблицы (ключей, значений, метатабельных).Например, у вас может быть подтаблица, чей метод deepcopy
не копирует метатаблицу.Вот базовая версия, в которой для подтаблицы используется тот же метод deepcopy
:
local block = {}
function block:deepcopy()
if type(self) == 'table' then
local copy = {}
for key, value in pairs(self) do
copy[self.deepcopy(key)] = self.deepcopy(value)
end
return setmetatable(copy, self.deepcopy(getmetatable(self)))
else
return self
end
end
block.a = { a = 10, deepcopy = block.deepcopy }
block:deepcopy() -- works
block.a = { a = 10 }
block:deepcopy() -- error: "attempt to call a nil value (field 'deepcopy')"
Но вам не нужно вообще переписывать функцию, чтобы использовать ее в объектно-ориентированном стиле.Попробуйте использовать ваше первое определение deepcopy
.Выполните object.deepcopy = deepcopy
, а затем позвоните object:deepcopy()
, и вы получите копию объекта.