SoFunction
Updated on 2025-04-06

Example explanation of functions, variable parameters, local functions, tail recursive optimization and other examples in Lua

1. Function

In Lua, functions are used as "First-Class Value", which means that functions can be stored in variables, can be passed to other functions through parameters, or as return values ​​of functions (analogous to function pointers in C/C++). This feature gives Lua great flexibility.
 
Lua provides good support for functional programming and can support nested functions.
 
In addition, Lua can not only call functions written by Lua, but also functions written by C (all Lua's standard libraries are written in C).
 
Define a function

Copy the codeThe code is as follows:

function hello()
print('hello')
end

The hello function does not receive parameters, and calls: hello(). Although hello does not receive parameters, you can also pass parameters: hello(32)
 
In addition, if you only pass one parameter, it can be simplified into the call form of functionname arg (note that the value is not OK)

Copy the codeThe code is as follows:

> hello '3'
hello
> hello {}
hello
> hello 3
stdin:1: syntax error near '3'

 
Also, it does not apply to variable names.
Copy the codeThe code is as follows:

> a = 21
> print a
stdin:1: syntax error near 'a'

 
In addition, Lua function does not support the default parameters, and it can be solved very conveniently using or (similar to Javascript)
Copy the codeThe code is as follows:

> function f(n)
>> n = n or 0
>> print(n)
>> end
> f()
0
> f(1)
1

Lua supports returning multiple values, which is very similar to Python in form:

Copy the codeThe code is as follows:

> function f()
>> return 1,2,3
>> end
> a,b,c = f()
> print(a .. b .. c)
123

 
The return value of the function call can be used in the table:
Copy the codeThe code is as follows:

> t = {f()}
> print(t[1], t[2], t[3])
1        2        3
 
It can be seen that the three values ​​returned by f() are called the three elements of the table, but this is not always the case:
Copy the codeThe code is as follows:

> t = {f(), 4}
> print(t[1], t[2], t[3])
1        4        nil

This time, the 1, 2, 3 returned by f() only has 1 elements called table;
Copy the codeThe code is as follows:

> t = {f(), f()}
> print(t[1], t[2], t[3], t[4], t[5])
1        1        2        3        nil

 
In short: Only the last item will use all return values ​​in full (if it is a function call).
 
For functions without return values, you can use (f()) to force return a value (nil)
Copy the codeThe code is as follows:

> function g()
>> end
> print(g())
 
> print((g()))
nil

In fact, a call in the form of (f()) returns one and only returns one value
Copy the codeThe code is as follows:

> print((f()))
1
> print(f())
1        2        3

2. Variable length parameters

Lua supports programming parameters and is easy to use (with the help of table and multiple assignments)

Copy the codeThe code is as follows:

> function f(...)
for k,v in ipairs({...}) do
print(k,v)
end
end
> f(2,3,3)
1        2
2        3
3        3

Using multiple assignments
Copy the codeThe code is as follows:

> function sum3(...)
>> a,b,c = ...
>> a = a or 0
>> b = b or 0
>> c = c or 0
>> return a + b +c
>> end
> =sum3(1,2,3,4)
6
> return sum3(1,2)
3

Usually, when traversing variable-length parameters, only {…} is needed, but variable-length parameters may contain some nil; then you can use the select function to access variable-length parameters: select('#', ...) or select(n, ...)

select('#', ...) returns the length of the variable parameter, select(n, ...) is used to access the parameters from n to select('#', ...)

Copy the codeThe code is as follows:

> =select('#', 1,2,3)
3
> return select('#', 1,2, nil,3)
4
> =select(3, 1,2, nil,3)
nil        3
> =select(2, 1,2, nil,3)
2        nil        3

Note: Lua5.0 does not provide... expressions, but use an implicit local table variable arg to receive all variable length parameters, indicating the number of parameters;

3. Functional programming

The function can be assigned a First-Class Value to a variable, and the latter is used to call it.

Copy the codeThe code is as follows:

> a = function() print 'hello' end
> a()
hello
> b = a
> b()
hello

Anonymous functions
Copy the codeThe code is as follows:

> g = function() return function() print 'hello' end end
> g()()
hello

Function g returns an anonymous function;
 
Closures are an important feature of functional programming, and Lua also supports them.
Copy the codeThe code is as follows:

> g = function(a) return function() print('hello'.. a); a = a + 1 end end
> f = g(3)
> f()
hello3
> f()
hello4

4. Local functions

Local functions can be understood as functions that are valid in the current scope. You can use local variables to refer to a function:

Copy the codeThe code is as follows:

> do
>> local lf = function() print 'hello' end
>> lf()
>> end
hello
> lf()
stdin:1: attempt to call global 'lf' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: in ?

It should be noted that the processing of recursive functions

Copy the codeThe code is as follows:

> do
local lf = function(n)
if n <= 0 then
return
end
print 'hello'
n = n -1
lf(n)
end
lf(3)
end
hello
stdin:8: attempt to call global 'lf' (a nil value)
stack traceback:
stdin:8: in function 'lf'
stdin:9: in main chunk
[C]: in ?

Instead, you should first declare local lf, and perform assignment
Copy the codeThe code is as follows:

do
local lf;
lf = function(n)
if n <= 0 then
return
end
print 'hello'
n = n -1
lf(n)
end
lf(3)
end
hello
hello
hello

Lua supports a definition form of local function(…) … end:
Copy the codeThe code is as follows:

> do
local function lf(n)
if n <= 0 then
return
end
print 'hello'
n = n -1
lf(n)
end
lf(3)
end
hello
hello
hello
> lf(3)
stdin:1: attempt to call global 'lf' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: in ?

5. Tail call

The so-called tail call means that one function returns the return value of another function:

Copy the codeThe code is as follows:

function f()

return g()
end
 
Because after calling g(), no code is executed in f(), there is no need to retain the call information of f(); Lua has made such optimization, which is called "tail call elimination". After g() returns, the control point returns directly to the place where f() is called.
 
This optimization is very beneficial for tail recursion. Usually recursion means the continuous growth of the caller, which may even cause stack overflow; while tail recursion provides optimization conditions, and the compiler can optimize the caller.
 
The following recursive function does not use tail recursion, and the parameters are large numbers, stack overflows:
Copy the codeThe code is as follows:

> function f(n)
>> if n <= 0 then
>> return 0
>> end
>> a = f(n-1)
>> return n * a
>> end
> f(10000000000)
stdin:5: stack overflow
stack traceback:
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
...
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:5: in function 'f'
stdin:1: in main chunk
[C]: in ?

Optimized to tail recursion
Copy the codeThe code is as follows:

function f(n, now)
if n <= 0 then
return now
end
 
return f(n-1, now*n)
end
f(10000000000, 1)

If you run for a long time, there will be no stack overflow;