`
hulianwang2014
  • 浏览: 692460 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

Lua基础 函数(一)

 
阅读更多

在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



水平有限,如果有朋友发现错误,欢迎留言交流。




分享到:
评论

相关推荐

    5-lua基础篇-函数

    5_lua基础篇_函数

    lua基础学习文档

    lua基本文档,适合初学时,包含lua函数库 lua模式匹配 lua文件处理 lua表和元方法

    Lua 基础教程(九)函数.pdf

    Lua 基础教程(九)函数

    lua 中的eclipse插件lua development tools,在原有的基础上实现工程函数跳转及提示

    lua 中的eclipse插件lua development tools,在原有的基础上实现工程函数跳转及提示

    Lua中函数与面向对象编程的基础知识整理

    函数在面对对象的编程中又被叫做方法,会受到作用域的制约,Lua中具有类等面向对象的特性,接下来我们就来看一下Lua中函数与面向对象编程的基础知识整理

    Lua 入门教程

    Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua 是巴西里约热内卢天主教大学(Pontifical Catholic ...

    Lua脚本在游戏引擎中的应用

    Lua是一种免费、开放的中间代码型的脚本语言,作者在研究了它的结构和 特点的基础上,对Lua运行环境中的堆栈结构进行了分析,由于引擎与Lua脚本 均能够操作堆栈中的数据,因此通过把堆栈作为两者信息传递的中间层,...

    Lua 5.0 Reference Manual(Revision 1.0) - PDF

    Lua脚本能够很容易被C/C++代码调用,同时也能够反过来调用C/C++的函数,这使得Lua在应用程序中被广泛应用,其中的一个重要应用就是作为游戏脚本。众所周知,Lua最著名的应用是暴雪娱乐公司(Blizzard)的网络游戏...

    lua基础知识

    有关lua的基础知识,内容包括函数库,捕获,文件处理等。

    Lua 5.0 Reference Manual(Revision 1.0) - ZIP

    Lua脚本能够很容易被C/C++代码调用,同时也能够反过来调用C/C++的函数,这使得Lua在应用程序中被广泛应用,其中的一个重要应用就是作为游戏脚本。众所周知,Lua最著名的应用是暴雪娱乐公司(Blizzard)的网络游戏...

    Programming In Lua First Edition(Finalized Revision 2.0) - 7Z

    Lua脚本能够很容易被C/C++代码调用,同时也能够反过来调用C/C++的函数,这使得Lua在应用程序中被广泛应用,其中的一个重要应用就是作为游戏脚本。众所周知,Lua最著名的应用是暴雪娱乐公司(Blizzard)的网络游戏...

    LUA5.1 脚本语言 编译执行源码

    Lua从一开始就是作为一门方便嵌入(其它应用程序)并可扩展的轻量级脚本语言来设计的,因此她一直遵从着简单、小巧、可移植、快速的原则,官方实现完全采用ANSI C编写,能以C程序库的形式嵌入到宿主程序中。Lua的每个...

    Lua中文教程(pdf版)

    25.2 调用Lua函数.........193 25.3 通用的函数调用...195 第26章调用C函数..........198 26.1 C 函数..198 26.2 C 函数库................200 第27章撰写C函数的技巧..................203 27.1 数组操作.......

    Programming In Lua First Edition(Finalized Revision 2.0) - PDF

    Lua脚本能够很容易被C/C++代码调用,同时也能够反过来调用C/C++的函数,这使得Lua在应用程序中被广泛应用,其中的一个重要应用就是作为游戏脚本。众所周知,Lua最著名的应用是暴雪娱乐公司(Blizzard)的网络游戏...

    详解Lua中的数组概念知识

    主要介绍了Lua中的数组概念知识,是Lua入门学习中的基础,需要的朋友可以参考下

    在Lua程序中使用MySQL的教程

    主要介绍了在Lua程序中使用MySQL的教程,是Lua入门学习中的基础知识,需要的朋友可以参考下

    基于串口屏LUA脚本—文本读取功能V1.0.pdf

    本章节主要通过 LUA 教程 demo 讲述如何基础运算和字符处理函数的使用以及编写程序的注意事项。本文将分为以下是 3 个阶段讲述教程 DEMO 是如何实现的:

    lua 程序设计学习.doc 版

    25.2 调用Lua函数 25.3 通用的函数调用 第26章 调用C函数 26.1 C 函数 26.2 C 函数库 第27章 撰写C函数的技巧 27.1 数组操作 27.2 字符串处理 27.3 在C函数中保存状态 27.3.1 The Registry 27.3.2 References 27.3.3...

    LuaQuickStartGuide:Lua快速入门指南的源代码-lua source code

    一个简短的指南,适合想要学习Lua编程的任何人。 不管您现有的技能水平如何,都可以通过Lua了解编程基础。 目录 第1章:Lua简介 本章介绍什么是Lua以及如何在任何操作系统上设置Lua环境。 Lua不受任何操作系统限制,...

    lua-mtstates:多线程Lua状态(请参阅

    这个包提供了一种从Lua内部创建新Lua状态的方法,以便在任意线程中使用它们。 该实现独立于基础线程库(例如或 )。 一般原则是通过在此状态下运行设置函数来准备状态,该设置函数返回回调函数,此后可以从不同...

Global site tag (gtag.js) - Google Analytics