Love2D: Подробнее о функциях

Руководство по Lua 5.1

Объявление функций

Функции создаются при помощи ключевого слова function
    function function_name ( args )
    body  -- тело функции
    end 
Пример простой функции, принимающей один аргумент и возвращающей его удвоенное значение:
    > foo = function (n) 
    > return n*2 
    > end
    > = foo(7)
    14
В скобках указываются передаваемые в функцию аргументы (параметры).
Возвращаемые пишутся после ключевого слова return
В Lua функции тоже значения. Взгляните ещё раз на пример выше. Мы не указали имени функции, а просто присвоили её переменной. В Lua с функциями можно обращаться как и с другими типами значений (такими как числа, строки и т.д.).
Функцию можно вызвать с помощью оператора (), перед которым пишется название функции или название переменной, которой назначили функцию; в самих круглых скобках указывается список аргументов, передаваемых в функцию.
Функции, как и таблицы, ссылочные значения.

Аргументы функции

Аргументы - значения, передаваемые в функцию во время её вызова. (Следует запомнить, что эти значения существуют только в пределах данной функции)
Функция может принимать любое кол-во аргументов, а может не иметь их вовсе.
    > f = function (op, a, b)
    >>  if op == 'add' then
    >>   return a + b
    >>  elseif op == 'sub' then
    >>   return a - b
    >>  end
    >>  error("invalid operation")
    >> end
    > g = function (value)
    >>  print(value)
    >> end
    > = f('add', 1, 2) -- аргументы в скобках разделяются запятыми
    3
    > = f('add', 1, 2, 123) -- лишние аргументы игнорируются
    3
    > = f('add', 1) -- неуказание нужного числа аргументов  само по себе не ошибка,
       - но в этом случае пропущенные аргументы становятся **nil**, что может вызвать ошибки в коде функции
    stdin:1: attempt to perform arithmetic on local 'b' (a nil value)
    > = g() -- если функция не принимает аргументы, нужно указывать пустые скобки ()
    nil
    > = g "example" -- скобки можно не указывать, если в функции один строковой аргумент
    example
    > = g {} 
    table: 0x820ee0

Возвращение нескольких значений

В Lua, в отличии от других языков, где из функции возвращается только одно значение, можно возвращать произвольное кол-во значений. Для этого просто нужно указать все возвращаемые значения через запятую после ключевого словаreturn
    > f = function ()
    >>  return "x", "y", "z" -- возвращает 3 значения
    >> end
    > a, b, c, d = f() -- присваивает 3 возвращаемых значения переменным, 4 переменная станет nil
    > = a, b, c, d
    x y z nil
    > a, b = (f()) -- заключив вызов функции в скобки, можно отменить множественный возврат значений
    > = a, b
    x, nil
    > = "w"..f() -- использование функции как подстроки также отменяет множественный вызов
    wx
    > print(f(), "w") -- также когда функция используется как аргумент в другой функции
    x w
    > print("w", f()) -- исключая ситуацию, когда функция стоит последним аргументом
    w x y z
    > print("w", (f())) -- в этом случае для отмены множественного возврата также можно использовать скобки
    w x
    > t = {f()} -- возвращаемые значения можно хранить в таблице
    > = t[1], t[2], t[3]
    x y z

Передача и возврат функций

Полезной особенностью Lua является возможность передачи функции как параметра и её возврат из других функций. Это позволяет вам изменять модифицировать код. Пример с функцией table.sort
    > list = {{3}, {5}, {2}, {-1}}
    > table.sort(list)
    attempt to compare two table values
    stack traceback:
            [C]: in function 'sort'
            stdin:1: in main chunk
            [C]: in ?
    > table.sort(list, function (a, b) return a[1] < b[1] end)
    > for i,v in ipairs(list) do print(v[1]) end
    -1
    2
    3
    5

Переменное число аргументов

Если вставить в конец списка аргументов ... (многоточие), тогда функция будет принимать переменное кол-во аргументов, также можно использовать ... (многоточие) в теле функции:
    > f = function (x, ...)
    >>  x(...)
    >> end
    > f(print, 1 2 3)
    1 2 3
Пример посложнее:
    > f=function(...) print(select("#", ...)) print(select(3, ...)) end
    > f(1, 2, 3, 4, 5)
    5
    3 4 5
Пример с таблицей:
    > f=function(...) tbl={...} print(tbl[2]) end
    > f("a", "b", "c")
    b
Можно "распаковать" таблицу с помощью функции unpack
    > f=function(...) tbl={...} print(table.unpack(tbl)) end 
    > f("a", "b", "c")
    a b c
    > f("a", nil, "c") -- nil приведёт к ошибке
Для решения вышеуказанной проблемы с nil можно использовать функцию table.pack (также функция добавляет в таблицу поле *.n*, в котором хранится число объектов в таблице)
    > f=function(...) tbl=table.pack(...) print(tbl.n, table.unpack(tbl, 1, tbl.n)) end
    > f("a", "b", "c")
    a b c
    > f("a", nil, "c")
    3 a nil c
Сокращения для имён функций:
    function f(...)
    end

    -- равняется

    f = function (...)
    end
Рекурсивные функции - функции вызывающие сами себя:
    function factorial(x)
      if x == 1 then
        return 1
      end
      return x * factorial(x-1)
    end
Можно создавать рекурсивные функции с множественным вызовом, к примеру: функция А вызывает функцию Б, которая вызывает функцию А... и так много-много раз.
Проблема в том, что при большом повторении вызовов тратиться много памяти.
Чтобы избежать этого, можно пользоваться "концевым вызовом"
Вызов в форме: " return functioncall" называется концевым вызовом. Lua также поддерживает концевой вызов «себя» (или рекурсивный концевой вызов): в этом случае вызванная функция использует стек вызывающей функции. Поэтому количество вложенных концевых вызовов может быть любым. Замете только, что концевой вызов стирает отладочную информацию о вызывающей функции. Синтаксис концевого вызова допускает только единичный вызов функции после оператора return. Таким образом, return вернет в точности тот результат, что вернет вызов функции. Ни один из представленных ниже примеров не является допустимым концевым вызовом и не подходит для решения проблемы множественного вызова:
     return (f(x))        -- список-результат обрезается
     return 2 * f(x)      -- удвоение результата функции
     return x, f(x)       -- возвращается несколько значений
     f(x); return         -- результат вызова отбрасывается
     return x or f(x)     -- список-результат обрезается
Типичные примеры концевого вызова:
    return f(arg) 
    return t.f(a+b, t.x) 
А вот пример нашей старой функции с вычислением факториала, только с использованием рекурсивно-концевого метода:
    function factorial_helper(i, acc)
      if i == 0 then
        return acc
      end
      return factorial_helper(i-1, acc*i)
    end

    function factorial(x)
      return factorial_helper(x, 1)
    end
данная статья является вольным переводом с сайта lua-users.org
с возможными дополнениями и изменениями

Просмотров: 1 845

Комментарии пока отсутcтвуют