В чем разница между этими двумя примерами Lua?Один лучше? - PullRequest
5 голосов
/ 12 декабря 2010

Я только начинаю с Луа.В примере, который я изучаю из ( открытого источника Ghosts & Monsters Corona ), я неоднократно вижу этот паттерн.Есть ли реальные преимущества в этом?Почему бы вам просто не пропустить функцию вместе и сделать это:

local director = require("director")

local mainGroup = display.newGroup()

mainGroup:insert(director.directorView)

local openfeint = require ("openfeint")
openfeint.init( "App Key Here", "App Secret Here", "Ghosts vs. Monsters", "App ID Here" )

director:changeScene( "loadmainmenu" )

Есть ли какая-то неявная выгода для первого стиля по сравнению со вторым?Спасибо!

Ответы [ 4 ]

8 голосов
/ 12 декабря 2010

Это какое-то соглашение, которое рекомендуют опытные программисты Lua, или есть реальные преимущества в этом?

Это не типично. Преимущество в том, что состояние объекта является частным, но этого недостаточно, чтобы рекомендовать его.

Я вижу эту модель неоднократно.

Я никогда не видел этого раньше, и это происходит только один раз в источнике, который вы опубликовали.

РЕДАКТИРОВАТЬ: Добавление ответа на вопрос, заданный в комментариях ниже этого сообщения.

Функция, которая обращается к внешним локальным переменным , связывает с этими переменными и называется «замыканием». Lua (по историческим причинам) называет эти связанные переменные «повышенными значениями». Например:

local function counter()
   local i = 1
   return function()
      print(i)
      i = i + 1
   end
end

local a, b = counter(), counter()
a() a() a() b() --> 1 2 3 1

a и b - это замыкания, связанные с различными копиями i, как вы можете видеть из вывода. Другими словами, вы можете думать о замыкании как о функции с его собственным частным состоянием. Вы можете использовать это для симуляции объектов:

function Point(x,y)
   local p = {}
   function p.getX() -- syntax sugar for p.getX = function()
      return x
   end
   function p.setX(x_)
      x = x_
   end
   -- for brevity, not implementing a setter/getter for y
   return p
end

p1 = Point(10,20)
p1.setX(50)
print(p1.getX())

Point возвращает таблицу замыканий, каждое из которых привязано к местным жителям x и y. Таблица не содержит состояния точки, самих замыканий, через их значения вверх. Важным моментом является то, что каждый раз, когда вызывается Point, он создает новых замыканий, что не очень эффективно, если у вас большое количество объектов.

Другим способом создания классов в Lua является создание функций, которые принимают таблицу в качестве первого аргумента с сохранением состояния в таблице:

function Point(x,y)
   local p = {x=x,y=y}
   function p:getX() -- syntax sugar for p.getX = function(self)
      return self.x
   end
   function p:setX(x)
      self.x = x
   end
   return p
end

p1 = Point(10,20)
p1:setX(50) -- syntax sugar for p1.setX(p1, 50)
print(p1:getX()) -- syntax sugar for p1.getX(p1)

Пока что мы все еще создаем новые копии каждого метода, но теперь, когда мы не полагаемся на повышенные значения для состояния, мы можем исправить это:

PointClass = {}
function PointClass:getX() return self.x end
function PointClass:setX(x) self.x = x end
function Point(x,y)
   return {
      x = x,
      y = y,
      getX = PointClass.getX,
      setX = PointClass.getY,
   }
end

Теперь методы создаются один раз, и все Point экземпляров имеют одинаковые замыкания. Еще лучший способ сделать это - использовать средство метапрограммирования Lua, чтобы новые экземпляры Point автоматически искали в PointClass методы, не найденные в самом экземпляре:

PointClass = {}
PointClass.__index = PointClass -- metamethod
function PointClass:getX() return self.x end
function PointClass:setX(x) self.x = x end
function Point(x,y)
   return setmetatable({x=x,y=y}, PointClass)
end

p1 = Point(10,20)
-- the p1 table does not itself contain a setX member, but p1 has a metatable, so 
-- when an indexing operation fails, Lua will look in the metatable for an __index
-- metamethod. If that metamethod is a table, Lua will look for getX in that table,
-- resolving p1.setX to PointClass.setX.
p1:setX(50)

Это более идиоматический способ создания классов в Lua. Он более эффективен в памяти и более гибок (в частности, упрощает реализацию наследования).

3 голосов
/ 17 декабря 2010

Я часто пишу свои собственные сценарии Lua таким образом, потому что это улучшает читабельность в этом случае:

function main()
    helper1( helper2( arg[1] ) )
    helper3()
end

function helper1( foo )
    print( foo )
end

function helper2( bar )
    return bar*bar
end

function helper3()
    print( 'hello world!' )
end

main()

Таким образом, «основной» код находится сверху, но я все еще могу определить необходимые глобальные функциидо того, как он запустится.

Простой трюк, правда.Я не могу придумать никаких причин сделать это, кроме читабельности.

1 голос
/ 26 декабря 2010

Первый стиль может быть использован слишком плохо для удобства чтения, но я бы предпочел дать функции какое-то значимое имя вместо main или просто обойтись без функции.

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

0 голосов
/ 12 декабря 2010

Я не вижу особого смысла в первом стиле, как вы его показали. Но если он говорит что-то вроде if arg then main() end внизу, сценарий может (просто может быть) использоваться в качестве загружаемой «библиотеки» в дополнение к тому, чтобы быть автономным сценарием. Тем не менее, имея main(), как этот, пахнет C, а не Lua; Я думаю, что вы правы, чтобы допросить это.

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