continuing with LUA..
Functions are the main mechanism for abstraction of statements and expressions in Lua. Functions can both carry out a specific task (what is sometimes called procedure or subroutine in other languages) or compute and return values. In the first case, we use a function call as a statement; in the second case, we use it as an expression:
print(8*9, 9/8) a = math.sin(3) + math.cos(10) print(os.date())In both cases, we write a list of arguments enclosed in parentheses. If the function call has no arguments, we must write an empty list
()
to indicate the call. There is a special case to this rule: If the function has one single argument and this argument is either a literal string or a table constructor, then the parentheses are optional:print "Hello World" <--> print("Hello World") dofile 'a.lua' <--> dofile ('a.lua') print [[a multi-line <--> print([[a multi-line message]] message]]) f{x=10, y=20} <--> f({x=10, y=20}) type{} <--> type({})
Lua also offers a special syntax for object-oriented calls, the colon operator. An expression like
o:foo(x)
is just another way to write o.foo(o, x)
, that is, to call o.foo
adding o
as a first extra argument. In Chapter 16 we will discuss such calls (and object-oriented programming) in more detail.
Functions used by a Lua program can be defined both in Lua and in C (or in any other language used by the host application). For instance, all library functions are written in C; but this fact has no relevance to Lua programmers. When calling a function, there is no difference between functions defined in Lua and functions defined in C.
As we have seen in other examples, a function definition has a conventional syntax; for instance
-- add all elements of array `a' function add (a) local sum = 0 for i,v in ipairs(a) do sum = sum + v end return sum endIn that syntax, a function definition has a name (
add
, in the previous example), a list of parameters, and a body, which is a list of statements.
Parameters work exactly as local variables, initialized with the actual arguments given in the function call. You can call a function with a number of arguments different from its number of parameters. Lua adjusts the number of arguments to the number of parameters, as it does in a multiple assignment: Extra arguments are thrown away; extra parameters get nil. For instance, if we have a function like
function f(a, b) return a or b endwe will have the following mapping from arguments to parameters:
CALL PARAMETERS f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 (5 is discarded)Although this behavior can lead to programming errors (easily spotted at run time), it is also useful, especially for default arguments. For instance, consider the following function, to increment a global counter.
function incCount (n) n = n or 1 count = count + n endThis function has 1 as its default argument; that is, the call
incCount()
, without arguments, increments count
by one. When you call incCount()
, Lua first initializes n
with nil; the or
results in its second operand; and as a result Lua assigns a default 1 to n
.5.3 – Named Arguments
The parameter passing mechanism in Lua is positional: When we call a function, arguments match parameters by their positions. The first argument gives the value to the first parameter, and so on. Sometimes, however, it is useful to specify the arguments by name. To illustrate this point, let us consider the function
rename
(from the os
library), which renames a file. Quite often, we forget which name comes first, the new or the old; therefore, we may want to redefine this function to receive its two arguments by name:-- invalid code rename(old="temp.lua", new="temp1.lua")Lua has no direct support for that syntax, but we can have the same final effect, with a small syntax change. The idea here is to pack all arguments into a table and use that table as the only argument to the function. The special syntax that Lua provides for function calls, with just one table constructor as argument, helps the trick:
rename{old="temp.lua", new="temp1.lua"}Accordingly, we define
rename
with only one parameter and get the actual arguments from this parameter:function rename (arg) return os.rename(arg.old, arg.new) end
This style of parameter passing is especially helpful when the function has many parameters, and most of them are optional. For instance, a function that creates a new window in a GUI library may have dozens of arguments, most of them optional, which are best specified by names:
w = Window{ x=0, y=0, width=300, height=200, title = "Lua", background="blue", border = true }The
Window
function then has the freedom to check for mandatory arguments, add default values, and the like. Assuming a primitive _Window
function that actually creates the new window (and that needs all arguments), we could define Window
as follows:function Window (options) -- check mandatory options if type(options.title) ~= "string" then error("no title") elseif type(options.width) ~= "number" then error("no width") elseif type(options.height) ~= "number" then error("no height") end -- everything else is optional _Window(options.title, options.x or 0, -- default value options.y or 0, -- default value options.width, options.height, options.background or "white", -- default options.border -- default is false (nil) ) end
No comments:
Post a Comment