Некоторые вопросы о "Закрытии" в Луа - PullRequest
0 голосов
/ 04 августа 2011

Вот мой код, я путаю локальную переменную 'count' в функции возврата (c1, c2) с памятью и где они хранятся?

function make_counter()
  local count = 0
  return function()
    count = count + 1
    return count
  end
end
c1 = make_counter()
c2 = make_counter()
print(c1())--print->1
print(c1())--print->2
print(c1())--print->3

print(c2())--print->1
print(c2())--print->2

Ответы [ 3 ]

4 голосов
/ 04 августа 2011

в функции возврата (c1, c2) с памятью и где они хранятся?

Хранится в замыкании!

c1 isне замыкание, это функция, возвращаемая make_counter().Закрытие явно нигде не объявлено.Это комбинация функции, возвращаемой make_counter(), и «свободных переменных» этой функции.См. замыкания @ Википедия , в частности реализацию :

Замыкания обычно реализуются с помощью специальной структуры данных, которая содержит указатель на код функции плюспредставление лексической среды функции (например, набора доступных переменных и их значений) в момент создания замыкания.

2 голосов
/ 04 августа 2011

Я не совсем уверен, что именно вы спрашиваете, но я попытаюсь объяснить, как работают замыкания.

Когда вы делаете это в Lua:

function() <some Lua code> end

Вы создаете значение . Значения - это такие вещи, как число 1, строка «строка» и т. Д.

Значения неизменны. Например, число 1 всегда является числом 1. Оно никогда не может быть числом два. Вы можете добавить 1 к 2, но это даст вам новое число 3. То же самое касается строк. Строка "string" является строкой и всегда будет этой конкретной строкой. Вы можете использовать функции Lua, чтобы убрать все символы «g» в строке, но это создаст новую строку «strin».

Функции являются значениями , так же как число 1 и строка "строка". Значения могут храниться в переменных. Вы можете хранить число 1 в нескольких переменных. Вы можете хранить строку «string» в нескольких переменных. И то же самое относится ко всем другим видам значений, включая функции.

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

Синтаксис {} создает таблицу Lua, которая является значением. Эта таблица отличается от любой другой таблицы, даже от других пустых таблиц. Тем не менее, вы можете положить разные вещи в таблицах. Это не меняет уникальное значение таблицы, но оно меняет то, что хранится в этой таблице. Каждый раз, когда вы выполняете {}, вы получаете новую уникальную таблицу. Так что если у вас есть следующая функция:

function CreateTable()
    return {}
end

Будет верно следующее:

tableA = CreateTable()
tableB = CreateTable()
if(tableA == tableB) then
    print("You will never see this")
else
    print("Always printed")
end

Хотя tableA и tableB являются пустыми таблицами (содержат одно и то же), они являются различными таблицами. Они могут содержать одно и то же, но имеют разные значения.

То же самое относится и к функциям. Функции в Lua часто называют «замыканиями», особенно если функция имеет содержимое. Функции получают содержимое в зависимости от того, как они используют переменные. Если функция ссылается на локальную переменную, которая находится в области действия в том месте, где эта функция создается (помните: синтаксис function() end создает функцию каждый раз, когда вы вызываете ее ), тогда функция будет содержать ссылку к этой локальной переменной.

Но локальные переменные выходят из области видимости, в то время как значение функции может жить (в вашем случае вы его возвращаете). Следовательно, объект функции, замыкание, должен содержать ссылку на эту локальную переменную, которая заставит его продолжать существовать, пока само замыкание не будет отброшено.

Где хранятся значения? Это не имеет значения; только закрытие может получить к ним доступ (хотя есть путь через C Lua API или через Lua Debug API). Таким образом, в отличие от таблиц, где вы можете получить что угодно, замыкания могут действительно скрывать данные.

0 голосов
/ 03 января 2013

Lua Closures также можно использовать для реализации основанных на прототипах классов и объектов. Классы и объекты замыкания ведут себя немного иначе, чем обычные классы Lua, и их метод вызова несколько отличается:

-- closure class definition

StarShip = {}

function StarShip.new(x,y,z)
    self = {}

    local dx, dy, dz
    local curx, cury, curz
    local engine_warpnew

    cur_x = x; cur_y = y; cur_z = z

    function setDest(x,y,z)
        dx = x; dy=y; dz=z;
    end

    function setSpeed(warp)
        engine_warpnew = warp
    end

    function self.warp(x,y,z,speed)
        print("warping to ",x,y,x," at warp ",speed)
        setDest(x,y,z)
        setSpeed(speed)
    end

    function self.currlocation()
        return {x=cur_x, y=cur_y, z=cur_z}
    end

    return self
end

enterprise = StarShip.new(1,3,9)

enterprise.warp(0,0,0,10)

loc = enterprise.currlocation()

print(loc.x, loc.y, loc.z)

Создает следующий вывод:

Деформация до 0 0 0 при деформации 10 1 3 9

Здесь мы определяем прототип объекта "StarShip" как пустую таблицу.

Затем мы создаем конструктор для StarShip в «новом» методе. Первое, что он делает, это создает таблицу замыкания под названием self, которая содержит методы объекта. Все методы в замыкании (определенные как «функция self.») «Закрыты» или определены для всех значений, доступных конструктору. Вот почему это называется закрытием. Когда конструктор завершен, он возвращает объект замыкания "return self".

Здесь можно найти гораздо больше информации об объектах на основе замыканий:

http://lua -users.org / вики / ObjectOrientationClosureApproach

...