在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。下面有3个例子,分别将函数当作一条语句;当作表达式(后面两个是一类)。
print(8*9, 9/8) --> 72 1.125
a = math.sin(3) + math.cos(10) --> a = -0.69795152101659
print(os.date()) --> Sat Mar 9 12:14:08 2013
函数如果带参数,那么就要用(arg1, arg2,...)括起来,如果没有参数,就写个空(),说明这是个函数调用。
特例,如果函数只有一个参数,并且参数类型是字符串或者table,那么()可以省略,如下示例:
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支持面向对象,操作符为冒号‘:’。o:foo(x) <==> o.foo(o, x),这个在后面会专门写一篇文章。
Lua程序可以调用C语言或者Lua实现的函数。Lua基础库中的所有函数都是用C实现的。调用一个用C实现的函数,和调用一个用Lua实现的函数,二者没有任何区别。
Lua函数的定义语法比较常规,如下示例:
function add(a)
local sum = 0
for i, v in ipairs(a) do
sum = sum + v
end
return sum
end
函数的参数跟局部变量一样,用传入的实参来初始化,多余的实参被丢弃,多余的形参初始化为nil。示例如下:
function f(a, b) return a or b end
f(3) -- a=3, b=nil
f(3, 4) -- a=3, b=4
f(3, 4, 5) -- a=3, b=4 (5被丢弃)
虽然Lua可以处理这样的情况,但是不鼓励这种传入错误数量参数的函数调用,可能会使程序运行时有点小问题。不过,有些情况下,这个特性可以加以利用,例如下面示例的默认参数:
1.多返回值
不同于常规函数,Lua的函数可以返回多个返回值。一些Lua中预定义的函数可以返回多个返回值。例如string.find函数,在string中匹配一个sub-string,string.find返回sub-string的起始位置和结束位置。利用多赋值语句来获取函数的多个返回值。
用Lua写的函数也可以返回多个返回值,如下示例,查找array中的最大值,并返回其位置和值
Lua会根据实际情况来使函数的返回值个数适应调用处的期望。
1)如果一个函数调用作为一条语句,所有的返回值都被丢弃
2)如果一个函数调用作为一个表达式,除了3)的情况,返回值只保留第一个
3)在多赋值,返回值作为实参来调用其他函数,table中,return语句中,这4种调用场景,如果函数调用作为其最后一个表达式,那么会保留所有的返回值,然后根据实际调用需要再纠正。
示例:
-- 多赋值,函数调用是最后一个表达式
x,y = foo2() -- x="a", y="b"
x = foo2() -- x="a", "b" is discarded
x,y,z = 10,foo2() -- x=10, y="a", z="b"
x,y = foo0() -- x=nil, y=nil
x,y = foo1() -- x="a", y=nil
x,y,z = foo2() -- x="a", y="b", z=nil
-- 多赋值,函数调用不是最后一个表达式,因此返回值只保留第一个
x,y = foo2(), 20 -- x="a", y=20
x,y = foo0(), 20, 30 -- x=nil, y=20, 30 is discarded
-- 返回值作为实参来调用其他函数
print(foo0()) -->
print(foo1()) --> a
print(foo2()) --> a b
print(foo2(), 1) --> a 1
print(1, foo2()) --> 1 a b
print(foo2() .. "x") --> ax (see next)
-- table中
t = {foo0()} -- t = {} (an empty table)
t = {foo1()} -- t = {"a"}
t = {foo2()} -- t = {"a", "b"}
-- table中,但是函数调用不是最后一个表达式
t = {foo0(), foo2(), 4} -- t[1] = nil, t[2] = "a", t[3] = 4
-- return语句中
function foo (i)
if i == 0 then return foo0()
elseif i == 1 then return foo1()
elseif i == 2 then return foo2()
end
end
print(foo(1)) --> a
print(foo(2)) --> a b
print(foo(0)) -- (no results)
print(foo(3)) -- (no results)
用括号来强制返回值个数为一个:
print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a
因此,括号千万别乱用,尤其是return后的值,如果用了括号,那么就只返回一个值。
函数unpack可以返回多个值,它传入一个array,然后返回array中的每一个值。
print(unpack{10,20,30}) --> 10 20 30
a,b = unpack{10,20,30} -- a=10, b=20, 30 is discarded
unpack的一个重要用法是泛型调用,提供了比C语言中更大的灵活性。在Lua中,如果你想调用一个函数f,传入可变数量的参数,很简单,
f(unpack(a))
unpack返回a中的所有值,并传给f作为参数,下面示例:
f = string.find
a = {"hello", "ll"}
print(f(unpack(a))) --> 3 4
Lua中的unpack是用C实现的。其实我们也可以用Lua来实现它
function unpack (t, i)
i = i or 1
if t[i] then
return t[i], unpack(t, i + 1)
end
end
2. 变参
Lua中的一些函数接受可变数量的参数,例如print函数。print函数是用C来实现的,但是我们也可以用Lua来实现变参函数。下面是一个示例:
function add (...)
local s = 0
for i, v in ipairs{...} do
s = s + v
end
return s
end
print(add(3, 4, 10, 25, 12)) --> 54
参数列表中的'...'指明该函数可以接受变参。我们可以将‘...’当作一个表达式,或者一个多返回值的函数(返回当前函数的所有参数)。例如
local a, b = ...
用可选参数的前两个初始化局部变量a,b的值。再看下面的例子,
function foo(a, b, c) <==> function foo(...) local a, b, c = ...
function id (...) return ... end
上面这个函数简单地返回它所有的参数。下面的例子,说明了一个跟踪函数调用的技巧
function foo1 (...)
print("calling foo:", ...)
return foo(...)
end
再看一个实用的例子。Lua提供了不同的函数来格式化文本string.formant和写文本io.write,我们可以简单地将二者合二为一。
function fwrite (fmt, ...)
return io.write(string.format(fmt, ...))
end
注意有一个固定的参数fmt。变参函数可能含有不定数目的固定参数,后面再跟变参。Lua会将前面的实参赋值给这些固定参数,剩下的实参才能当作变参看待。下面是几个示例:
CALL PARAMETERS
fwrite() -- fmt = nil, no varargs
fwrite("a") -- fmt = "a", no varargs
fwrite("%d%d", 4, 5) -- fmt = "%d%d", varargs = 4 and 5
如果想要迭代处理变参,可以用{...}来将所有的变参收集到一个table中。但是有时变参中可能含有非法的nil,我们可以用select函数。select函数有一个固定的参数selector,然后跟一系列的变参。调用的时候,如果selector的值为数字n,那么select函数返回变参中的第n个参数,否则selector的值为'#',select函数会返回可变参数的总数目。下面示例:
for i=1, select('#', ...) do
local arg = select(i, ...) -- get i-th parameter
<loop body>
end
注意,select("#", ...)返回变参的数目,包括nil在内。
3. 带名字的参数
Lua中函数的参数传递是基于位置的,当调用函数的时候,实参根据位置来匹配形参。但是,有的时候,根据名字来匹配更实用。例如,系统函数os.rename,我们会经常忘记新名字和旧名字哪个在前;为了解决这个问题,我们尝试重新定义这个函数。下面这个
-- invalid code
rename(old="temp.lua", new="temp1.lua")
上面这个代码是非法的,Lua并不支持这样的语法。但是我们可以修改一点点,来实现相同的效果。
function rename (arg)
return os.rename(arg.old, arg.new)
end
用这种方式来传递参数是很实用的,尤其是,当函数有多个参数,并且其中一些是可有可无时。例如,用GUI库创建一个新的窗口
w = Window{ x=0, y=0, width=300, height=200,
title = "Lua", background="blue",
border = true
}
Window函数可以检查必须的参数,并且给可选参数赋予默认值等。假设_Window函数可以用来创建一个新窗口,但是它必须要全部的参数。那我们就可以重新定义一个Window函数如下:
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
水平有限,如果有朋友发现错误,欢迎留言交流。
分享到:
相关推荐
1. **Lua与C++的交互接口**:Lua提供了一个名为`luaL_newstate`的API来创建一个新的Lua状态机,这是与C++交互的基础。然后,通过`luaL_openlibs`打开标准库,使Lua具备基本功能。 2. **注册C++函数到Lua**:使用`...
在C++程序中使用Lua,首先要创建一个Lua状态机(`lua_State*`),这是所有Lua操作的基础。通过`luaL_newstate()`函数可以创建一个新的Lua环境,并通过`luaL_openlibs()`打开标准库,这样就可以在C++中使用Lua的基本...
3. **函数与闭包**:Lua中的函数是第一类公民,可以作为参数传递,也可以作为返回值。闭包的概念则允许函数访问并修改其词法作用域内的变量。 4. **元编程**:Lua通过Metatables提供了一种灵活的元编程机制,可以...
它提供了一系列的函数,如`luaL_newstate`用于创建一个新的Lua环境,`luaL_openlibs`打开默认的库,以及`luaL_loadbuffer`或`luaL_dofile`用于加载和运行Lua脚本。 2. **进栈和出栈**: - **进栈**:将C/C++的数据...
在这个基础篇中,我们将深入探讨Lua中的函数机制,包括全局与局部变量、函数定义、局部函数、函数的赋值与匿名函数以及函数的多返回值。 首先,让我们来看一下**函数的定义**。在Lua中,函数的定义语法简洁明了,如...
这个"lua基础学习文档"涵盖了对初学者至关重要的几个主题:lua函数库、模式匹配、文件处理以及表和元方法。让我们逐一深入探讨这些核心概念。 1. Lua函数库: Lua标准库提供了一系列内置函数,方便用户进行各种常见...
本文将详细讲解如何在C++中调用Lua函数,并提供一个简单的源代码案例作为参考。 首先,我们需要了解C++与Lua交互的基础。Lua是一个轻量级的脚本语言,它的设计目标是易于嵌入到其他应用中,而C++则是一种通用的、...
### Lua基础教程(九)函数知识点详解 #### 一、函数概述 - **定义**:在Lua语言中,函数是一组语句的集合,用于执行一个特定的任务。 - **作用**:通过将代码分解成不同的函数,可以提高代码的复用性和可维护性。...
1. **Lua基础语法**:Lua是一种简洁、易读的脚本语言,它的基本语法包括变量(全局和局部)、数据类型(如数值、字符串、表、布尔值和nil)、运算符、控制结构(如if语句、while循环、for循环)等。理解这些基础是...
1. 初始化Lua环境:创建一个LuaState实例,这是执行Lua脚本的基础。 ```csharp using LuaInterface; ... Lua lua = new Lua(); ``` 2. 注册C#函数到Lua:为了让Lua脚本能够调用C#的方法,你需要先注册这些方法。例如...
要从C/C++中调用Lua函数,我们需要创建一个Lua状态机(lua_State*),这是所有交互的基础。例如: ```c #include <lua.h> #include #include int main() { lua_State *L = luaL_newstate(); luaL_openlibs(L);...
这个环境是所有 Lua 操作的基础,它是一个独立的执行上下文。 2. **打开标准库**:调用 `luaL_openlibs(state)` 将 Lua 标准库加载到新创建的环境中。这使得你可以使用如 print、math 等内置函数。 3. **加载脚本*...
- 帮助文档:可能包含LUA语言的基础教程和常见问题解答。 对于初学者,这样的练习器可以帮助他们快速上手,理解LUA的基本语法和特性。对于有一定经验的开发者,它也能作为一个便捷的测试平台,验证和调试代码片段。...
3. **函数与模块**:Lua中的函数是第一类公民,可以作为参数传递,也可以作为返回值。同时,Lua支持自定义模块,便于组织和重用代码。 4. **闭包与迭代器**:Lua的闭包机制使得函数可以访问并操作外部环境的变量,...
1. Lua语言基础:了解变量、表、函数、控制结构等基本概念。 2. Lua与C/C++的交互:理解如何在C/C++中注册和调用Lua函数,以及如何在Lua中调用C/C++函数。 3. Lua脚本调试:学会使用如luadoc之类的工具来生成和查看...
本教程旨在提供一个全面且深入的中文学习资源,帮助读者从零基础到熟练掌握Lua。 首先,我们从基础开始。Lua的核心概念包括变量、数据类型和控制结构。在Lua中,变量是动态类型的,无需预先声明。它支持五种基本...
### Lua基础学习笔记 #### 一、Lua简介与特点 Lua是一种轻量级且高效的脚本语言,广泛应用于游戏开发、网页应用、图形界面等领域。对于已有其他编程语言基础的学习者来说,掌握Lua通常较为迅速。Lua的设计哲学是...
在“lua基础笔记”中,我们可以探索以下关键知识点: 1. ** Lua语法基础 **:Lua的语法简洁明了,易于学习。变量声明不需要指定类型,其数据类型包括数字(浮点数和整数)、字符串、布尔值、表(类似数组或哈希表)...
综上所述,lua中的eclipse插件lua development tools(LDT)在原有功能的基础上,通过实现工程函数跳转及提示,极大地提升了Lua开发者的编码效率和代码质量。这些高级特性使得LDT成为Lua开发者不可或缺的工具之一,...
例如,"luabindings"是一个Delphi绑定到Lua C API的项目,它允许你在Delphi中直接调用Lua函数和访问Lua全局变量。 安装完成后,我们需要在Delphi项目中引入相关的单元文件,如`luabindings.pas`或`luapascalapi.pas...