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