求教一个Lua如何求函数最值问题问题

Lua教程(四):函数详解
转载 & & 投稿:junjie
这篇文章主要介绍了Lua教程(四):函数详解,本文讲解了多重返回值、变长参数、具名实参、闭合函数、匿名函数、非全局函数等内容,需要的朋友可以参考下
一、函数:
&&& 在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y)。唯一的差别是,如果函数只有一个参数,并且该参数的类型为字符串常量或table的构造器,那么圆括号可以省略,如print "Hello World"和f {x = 20, y = 20}。
&&& Lua为面对对象式的调用也提供了一种特殊的语法--冒号操作符。表达式o.foo(o,x)的另一种写法是o:foo(x)。冒号操作符使调用o.foo时将o隐含的作为函数的第一个参数。
&&& Lua中函数的声明方式如下:
& 代码如下:
&&& function add(a)
&&&&&&& local sum = 0
&&&&&&& for i, v in ipairs(a) do
&&&&&&&&&&& sum = sum + v
&&&&&&& end
&&&&&&& return sum
&&& 在以上声明中,包含了函数名(add),参数列表(a),以及函数体。需要说明的是,Lua中实参和形参的数量可以不一致,一旦出现这种情况,Lua的处理规则等同于多重赋值,即实参多于形参,多出的部分被忽略,如果相反,没有被初始化的形参的缺省值为nil。
&&& 1. 多重返回值:
&&& Lua支持返回多个结果值。如:
s,e = string.find("Hello Lua users","Lua")
print("The begin index is " .. s .. ", the end index is " .. e .. ".");
-- The begin index is 7, the end index is 9.
&&& 以上的代码示例只是演示了如何获取Lua函数的多个返回值,下面的示例将给出如何声明返回多个值的Lua函数。如:
function maximum(a)
&&& local mi = 1
&&& local m = a[mi]
&&& for i, val in ipairs(a) do
&&&&&&& if val & m then
&&&&&&&&&&& mi,m = i,val
&&&&&&& end
&&& return m,mi
print(maximum{8,10,23,12,5})
Lua会调整一个函数的返回值数量以适应不同的调用情况。若将函数调用作为一条单独语句时,Lua会丢弃函数的所有返回值。若将函数作为表达式的一部分来调用时,Lua只保留函数的第一个返回值。只有当一个函数调用是一系列表达式中的最后一个元素时,才能获得所有返回值。这里先给出三个样例函数,如:
&&& function foo0() end
&&& function foo1() return "a" end
&&& function foo2() return "a","b" end
&最后一个需要介绍的是Lua中unpack函数,该函数将接收数组作为参数,并从下标1开始返回该数组的所有元素。如:
& 代码如下:
&&& /& lua
&&& & print(unpack{10,20,30})
&&& 10& 20& 30
&&& & a,b = unpack{10,20,30}
&&& & print(a,b)
&&& 10& 20
&&& & string.find(unpack{"hello","ll"})& --等同于string.find("hello","ll")
&&& 在Lua中unpack函数是用C语言实现的。为了便于理解,下面给出在Lua中通过递归实现一样的效果,如:
function unpack(t,i)
&&& i = i or 1
&&&& if t[i] then
&&&&&&&& return t[i], unpack(t,i + 1)
2. 变长参数:
&&& Lua中的函数可以接受不同数量的实参,其声明和使用方式如下:
& 代码如下:
&function add(...)
&&& local s = 0
&&& for i, v in ipairs{...} do
&&&&&&& s = s + v
&&& return s
print(add(3,4,5,6,7))
--输出结果为:25
& 解释一下,函数声明中的(...)表示该函数可以接受不同数量的参数。当这个函数被调用时,所有的参数都被汇聚在一起,函数中访问它时,仍需用3个点(...)。但不同的是,此时这3个点将作为表达式来使用,如{...}表示一个由所有变参构成的数组。在含有变长参数的函数中个,同样可以带有固定参数,但是固定参数一定要在变长参数之前声明,如:
&&& function test(arg1,arg2,...)
&&&&&&& ...
&&& 关于Lua的变长参数最后需要说明的是,由于变长参数中可能包含nil值,因此再使用类似获取table元素数量(#)的方式获取变参的数量就会出现问题。如果要想始终获得正确的参数数量,可以使用Lua提供的select函数,如:
for i = 1, select('#',...) do& --这里'#'值表示让select返回变参的数量(其中包括nil)。
&&& local arg = select(i, ...) --这里的i表示获取第i个变参,1为第一个。
&&&& --do something
3. 具名实参:
&&& 在函数调用时,Lua的传参规则和C语言相同,并不真正支持具名实参。但是我们可以通过table来模拟,比如:
& 代码如下:
&&& function rename(old,new)
&&&&&&& ...
&&& 这里我们可以让上面的rename函数只接收一个参数,即table类型的参数,与此同时,该table对象将含有old和new两个key。如:
& 代码如下:
&&& function rename(arg)
&&&&&&& local old = arg.old
&&&&&&& local new = arg.new
&&&&&&& ...
&&& 这种修改方式有些类似于JavaBean,即将多个参数合并为一个JavaBean。然而在使用时,Lua的table存在一个天然的优势,即如果函数只有一个参数且为string或table类型,在调用该函数时,可以不用加圆括号,如:
& 代码如下:
&&& rename {old = "oldfile.txt", new = "newfile.txt"}
二、深入函数:
&&& 在Lua中函数和所有其它值一样都是匿名的,即它们都没有名称。在使用时都是操作持有该函数的变量,如:
& 代码如下:
&&& a = { p = print }
&&& a.p("Hello World")
&&& b = print
&&& b("Hello World")
&&& 在声明Lua函数时,可以直接给出所谓的函数名,如:
& 代码如下:
&&& function foo(x) return 2 * x end
&&& 我们同样可以使用下面这种更为简化的方式声明Lua中的函数,如:
& 代码如下:
&&& foo = function(x) return 2 * x end
&&& 因此,我们可以将函数理解为由语句构成的类型值,同时将这个值赋值给一个变量。由此我们可以将表达式"function(x) &body& end"视为一种函数的构造式,就想table的{}一样。我们将这种函数构造式的结果称为一个"匿名函数"。下面的示例显示了匿名函数的方便性,它的使用方式有些类似于Java中的匿名类,如:
& 代码如下:
&&& table.sort(test_table,function(a,b) return (a.name & b.name) end)
&&& 1. closure(闭合函数):
&&& 若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量,见如下示例:
function newCounter()
&&& local i = 0
&&& return function() --匿名函数
&&&&&&& i = i + 1
&&&&&&& return i
c1 = newCounter()
print("The return value of first call is " .. c1())
print("The return value of second call is " .. c1())
--输出结果为:
--The return value of first call is 1
--The return value of second call is 2
在上面的示例中,我们将newCounter()函数称为闭包函数。其函数体内的局部变量i被称为"非局部变量",和普通局部变量不同的是该变量被newCounter函数体内的匿名函数访问并操作。再有就是在函数newCounter返回后,其值仍然被保留并可用于下一次计算。再看一下下面的调用方式。
function newCounter()
&&& local i = 0
&&& return function() --匿名函数
&&&&&&& i = i + 1
&&&&&&& return i
c1 = newCounter()
c2 = newCounter()
print("The return value of first call with c1 is " .. c1())
print("The return value of first call with c2 is " .. c2())
print("The return value of second call with c1 is " .. c1())
--输出结果为:
--The return value of first call with c1 is 1
--The return value of first call with c2 is 1
--The return value of second call with c1 is 2
由此可以推出,Lua每次在给新的闭包变量赋值时,都会让不同的闭包变量拥有独立的"非局部变量"。下面的示例将给出基于闭包的更为通用性的用法:
&&& --这里将原有的文件打开函数赋值给"私有变量"oldOpen,该变量在块外无法访问。
&&& local oldOpen = io.open
&&& --新增一个匿名函数,用于判断本次文件打开操作的合法性。
&&& local access_OK = function(filename,mode) &检查访问权限& end
&&& --将原有的io.open函数变量指向新的函数,同时在新函数中调用老函数以完成真正的打开操作。
&&& io.open = function(filename,mode)
&&&&&&& if access_OK(filename,mode) then
&&&&&&&&&&& return oldOpen(filename,mode)
&&&&&&& else
&&&&&&&&&&& return nil,"Access denied"
&&&&&&& end
上面的这个例子有些类似于设计模式中装饰者模式。
&&& 2. 非全局函数:
&&& 从上一小节中可以看出,Lua中的函数不仅可以直接赋值给全局变量,同时也可以赋值给其他类型的变量,如局部变量和table中的字段等。事实上,Lua库中大多数table都带有函数,如io.read、math.sin等。这种写法有些类似于C++中的结构体。如:
& 代码如下:
&&& Lib = {}
&&& Lib.add = function(x,y) return x + y end
&&& Lib.sub = function(x,y) return x - y end
&&& 或者是在table的构造式中直接初始化,如:
& 代码如下:
&&& Lib = { add = function(x,y) return x + y end,
&&&&&&&&&&&&&& sub = function(x,y) return x - y end
&&&&&&&&&&&& }
&&& 除此之外,Lua还提供另外一种语法来定义此类函数,如:
& 代码如下:
&&& Lib = {}
&&& function Lib.add(x,y) return x + y end
&&& function Lib.sub(x,y) return x - y end
&&& 对于Lua中的局部函数,其语义在理解上也是非常简单的。由于Lua中都是以程序块作为执行单元,因此程序块内的局部函数在程序块外是无法访问的,如:
&&&& local f = function(x,y) return x + y end
&&&& --do something with f.
&&&& f(4,5)
&对于这种局部函数,Lua还提供另外一种更为简洁的定义方式,如:
& 代码如下:
&&& local function f(x,y) return x + y end
&&& 该写法等价于:
& 代码如下:
&&& local f
&&& f = function(x,y) return x + y end
&&& 3. 正确的尾调用:
&&& 在Lua中支持这样一种函数调用的优化,即“尾调用消除”。我们可以将这种函数调用方式视为goto语句,如:
& 代码如下:
&&& function f(x) return g(x) end
&&& 由于g(x)函数是f(x)函数的最后一条语句,在函数g返回之后,f()函数将没有任何指令需要被执行,因此在函数g()返回时,可以直接返回到f()函数的调用点。由此可见,Lua解释器一旦发现g()函数是f()函数的尾调用,那么在调用g()时将不会产生因函数调用而引起的栈开销。这里需要强调的是,尾调用函数一定是其调用函数的最后一条语句,否则Lua不会进行优化。然而事实上,我们在很多看似是尾调用的场景中,实际上并不是真正的尾调用,如:
& 代码如下:
&&& function f(x) g(x) end&&&&&&&&&&& --没有return语句的明确提示
&&& function f(x) return g(x) + 1& --在g()函数返回之后仍需执行一次加一的指令。
&&& function f(x) return x or g(x) --如果g()函数返回多个值,该操作会强制要求g()函数只返回一个值。
&&& function f(x) return (g(x))&&&& --原因同上。
&&& 在Lua中,只有"return &func&(&args&)"形式才是标准的尾调用,至于参数中(args)是否包含表达式,由于表达式的执行是在函数调用之前完成的,因此不会影响该函数成为尾调用函数。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具Lua检查函数的覆盖问题
Posted on 日, 21:30, by 那谁, under .
Lua里面可以实现类面向对象,这个在后面会分析到。前几天项目里面遇到的一个问题,在不同模块中的同名函数,由于都是挂在某个类下面,会出现后面加载的模块函数覆盖了前面的函数。简单的例子就是这样的:
首先定义一个基类obj,里面有一个名为test的函数:
module("obj", package.seeall)
function test()
print("in obj")
require("person")
其中obj.lua的最后一行加载的是一个名为person.lua的文件,它也挂在obj模块下,所以里面实现的函数也是obj类的函数:
module("obj")
function call_test()
local tbl = _G["obj"]
local fun = tbl["test"]
call_test()
function test()
print("in person")
call_test()
person.lua中定义了一个名为call_test的函数,用于在person的test函数的定义前后都调用一下obj类的test函数,发现在之前调用的是obj的test函数,而在这之后则是person模块中的test函数了。这说明obj类的test函数发生了覆盖现象。
这是使用脚本语言不得不面对的一个弊端:许多问题只有在运行到的时候才会发现。于是我们需要一个手段,在发现有函数覆盖的情况给出一个警告。我的做法是这样的:
module("obj")
local tmp = nil
function call_test()
local tbl = _G["obj"]
local fun = tbl["test"]
function check()
local tbl = _G["obj"]
local fun = tbl["test"]
if tmp == nil then
elseif tmp ~= fun then
print("override")
call_test()
function test()
print("in person")
call_test()
这个检查hardcode了需要检查是否出现覆盖的函数是test,实际中可以遍历一个模块表中的所有函数先做一个记录,后面再做判断。这个检查当然是很耗时的,所以可以加一个条件判断,仅在开发期做判断就好了。
Leave a Reply
我的其它出没地点
我的新浪微博
文章索引模板lua定义函数-好心游戏网-游戏门户
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
lua定义函数
你在执行时 c1 被赋予了这个匿名函数 所以每次调用c1都会输出这个每次都会自增的局部变量i 第一个问题: 你不要把lua 源代码里面的参数和lua扩展的c函数里面的参数混淆了...
呵呵&); end return M;
我们把game.lua这个模块里的全局环境设置为M,于是,我们直接定义函数的时候,不需要再带M前缀。 因为此时的全局环境就是M,不带前缀去定义变量...
谁说在Lua中只能调用写在上面的函数 在Lua中函数名只是一个普通的变量而已. 所以, 如果函数是全局函数, 只要直接用就可以了, 在前还是在后定义无所谓. 如果是局部变量函...
申明了一个局部变量,是table类型的 table内以字符串&encode&为下标的值 是一个函数 调用的时候直接访问_M.encode就可以了,或者可以把这个_M作为某个table的元...
lua中不自带这个函数 是你的lua function 或者c function
lua中关于时间的函数只有 os.time和os.date
把test函数编译成一个动态库方式,然后在lua中用ffi.load(libtest)这种方式是可以调用的! 你的采纳是我前进的动力, 记得好评和采纳,答题不易,互相帮助, 手机提问的朋友在客户端...
message, caption, MB_OK);
lua_pushnumber(L, result);
int __declspec(dllexport) libinit (lua_State* L)
lua_register(L, &msgbox&, lua_msgbox);
return 0...
正式的参数表现得就像在函数内部其他本地变量和在进入函数创建并在退出时销毁。 调用函数: 当创建一个Lua函数,给什么样的功能,必须做一个定义。要使用一个方法,将不得...
& 这篇文章主要介绍了Lua中的函数写法简明示例,本文是一篇个人学习笔记,简单的记录了Lua函数的写法,需要的朋友可以参考下 函数定义:用关键字function定义函数,以关...
static int ABC(lua_State *L)
&int n =lua_gettop(L);
&double sum =0;
&for (i=1;i&n;i++)
&&sum+=lua_tonumber(L,i);
OLED_P6x8Str_My(unsigned char x, y,unsigned char ch[]) {\n
unsigned char c[1];
int m=1000;
for(i=0;i&4;i++)\n
*c=(char)(input/m)+48;\n
OLED_P6x8Str(24+6*i+x,0+y,c);\
lua定义函数,RT,谁能帮微一下
我们在用找色的时候比较头痛的问题是很难找到一个色值能准确的和其它目标区别,如果想用多点找色又得把区域定得很小,只能判断是还是不是。我这个函数解决了上面的两个问题,我们可以用多个色值,进行大范围查找,这样既可以用多个色值减小误差,也可以在大的区域内找目标,而且因为用了以找主色为主线,找到才确定辅色的方式,效率大大提高,当然还有找图所没有的兼容性和便利性,辅色的数量可变更增加了函数应用范围。函数使用不
在过去的几十年里,宇宙大爆炸理论中的锂问题是一大难解之谜,因为科学家发现锂含量只有理论预言的三分之一。为什么最终锂含量与预测结果差了3倍多呢?为了解决这个问题,让我们来回顾一下宇宙大爆炸理论。大爆炸理论是迄今在科学界被广泛接受的关于宇宙起源的理论。宇宙大爆炸论有三大观测支持,分别是哈勃定律、宇宙微波背景辐射和原初元素丰度。宇宙微波背景辐射(CMB)宇宙微波背景辐射是支持大爆炸论的有力证据之一,经过
lua定义函数,RT,谁能帮微一下
lua定义函数,RT,谁能帮微一下
我用图解的方式,向你详细讲解VLOOKUP函数的使用全部使用方法,学完本文,如果你还不会用VLOOKUP函数,你来怼我!!VLOOKUP函数可以说是Excel中为数不多的神级函数之一,记得我是小白的年代看到花费我查找了2个小时的数据,高手1分钟不到就弄完了,那时的我于是我潜心学习,制作了VLOOKUP函数的宝典级用法,为的就是让你不再怀疑人生,自信的使用VLOOKUP函数。一、Vlookup函数的
VLOOKUP函数的作用:按列查找,最终返回该列所需查询列序所对应的值。VLOOKUP函数的语法:VLOOKUP(lookup_value,table_array,col_index_num,range_lookup)。(1)Lookup_value为需要在数据表第一列中进行查找的数值。Lookup_value 可以为数值、引用或文本字符串。当vlookup函数第一参数省略查找值时,表示用0查找。
同学,你好!你想一下,既然函数具有凹凸性,也就是说是凹凸不平的,那么它就一定是有导数的。只有函数与Y轴平行的时候才没有导数(与x轴平行的时候导数为0)。因为导数的几何意义就是函数切线的斜率。从定理上来看,利用一阶导数和二阶导数来判断的那就不用说了,那就肯定是有导数的。对于定义而言,尽管没有直接说这个函数可导,但是它利用的是自变量和因变量在两个端点的和再除以二来比较的,这个就绕回了我开头说的,这个函
转别人回答也是VS2015+BabeLua插件,不过就是好像调试不了,如果是写脚本的话还是很好用有调试功能的呢用LuaStudio,但是相对于VS感觉写的时候没那么舒服我也一边在用sublime3,但是现在还不知道怎么让它自动排列代码,而且也不能调试,写脚本可以和VS媲美甚至更舒服,就是不知道怎么自动排列其实我也想找一个好的工具,如果VS能调试Unity 的Lua脚本就好了
答:申明了一个局部变量,是table类型的 table内以字符串"encode"为下标的值 是一个函数 调用的时候直接访问_M.encode就可以了,或者可以把这个_M作为某个table的元表访问
答:这个其实不止是匿名函数的问题 这个的概念其实是涉及到了闭包 如果不太了解闭包可以暂时先不去考虑理解 函数A返回值是一个匿名的函数 这个匿名函数会改变函数A内的局部变量i 匿名函数每次被调用时 都会使A内的局部变量自增1并且返回这个值 你在...
答:换行符 (回车/换行) 可以用于搜索和替换。要指定换行符,在对话框中输入“^p”字符表示 回车/换行。 UltraEdit文本编辑并不是很实用,而16进制编辑是非常实用的!编程方面也还算可以!UE编辑器的设置非常全面,可以设置字体、间距、背景色、特殊字...
答:可以,就像变量一样使用--函数function g_func(param)end变量local g_number = 1--做事情function doSM(num, fn) --传进来的变量g_number local number = num --传进来的函数g_func fn(value)end--主函数function main() --把变量和函数传入doSM...
问:function newCounter() local i = 0 return function() i=i+1 return i ...答:其实这个例子 应该是一个计数器吧 本身也是闭包的一个演示例子 首先你要看newCounter这个函数的返回值 它的返回值 返回的不是一个具体的数字,而是一个函数 所以 如果直接print这个函数 得到的是function xxxx 当调用这个返回的函数才能得到这个值
答:一. lua调用C++ 在lua中是以函数指针的形式调用函数, 并且所有的函数指针都必须满足如下此种类型: typedef int (*lua_CFunction) (lua_State *L); 也就是说, 偶们在C++中定义函数时必须以lua_State为参数, 以int为返回值才能被Lua所调用. 但是不...
问:table可不可以存储函数(无论有没有返回值)呢? 例如 --------- list{}...答:可以用数字下标放 但我们更常用的方法是以字符串做下标 local t = {}t.fun = function() print(123) endt.fun()
答:除了楼上的回答,还可以这样,dofile("b.lua") 然后就可以在a.lua脚本中调用b.lua中的函数了。
答:先看一下select的使用案例 假设调用函数select(5,1,2,3,4,5,6,7,8) 理论上是返回5之后的所有 也就是5,6,7,8 但是为什么你的函数只返回了一个值呢 首先你要从你的赋值语句开始看 你的输出语句是print(i,arg) 只输出了2个参数 i和arg i是循环变量 ...
问:比如 我这里要多次调用test()函数 function test() local i=0; if (i&5)...答:1、把内容单独放一个文件里lua文件里 local i = 0 function test() if (i他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 如何求函数最值问题 的文章

 

随机推荐