随着对Lua使用的增加,开始关注很多该语言的细节,例如,怎样向Lua函数传递不同种类、不同数量的参数,怎样返回多种参数等等。今天主要介绍Lua函数的基本用法,包括可变参数的使用。
1. Lua函数格式
Lua函数定义格式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
function_body
return result_params_comma_separated
end
optional_function_scope为可选项,指定函数的作用域,若不指定,默认为global,全局作用域,也可根据需要设置为local。
function为函数关键字。
function_name:用户自定义函数名称。
argument1, argument2, argument3, ..., argumentn:函数参数,多个参数以逗号隔开。函数可包含0个参数,也可包含多个参数。
function_body:函数体,用户自定义函数语句块。
result_params_comma_separated:函数返回值,Lua函数可返回多个值,以逗号隔开。函数返回时,函数名和参数都pop出栈,然后将返回值依次压栈。
2. 函数使用示例
以下是一个C++调用Lua函数的例子。该例子的流程是:首先调用第一个Lua函数first_check(),根据该函数的返回值确定是否继续下一步调用,若继续,则继续调用第二个Lua函数main_logic()。其中,第一个Lua函数first_check()为已知参数类型的函数,且返回值只有一个;第二个Lua函数main_logic()包含未知参数,且含有多个返回值。
--固定参数,且只有一个返回值
function first_check(value, descript)
print("value = " .. value)
print("descript = " .. descript)
local result = false
if value > 45 then
result = true
else
result = false
end
print("first check result: ", result)
return result
end
--可变参数,且含有两个返回值。...代表可变参数
function main_logic(value, descript, ...)
local arg = {...}
num = #arg --#arg表示获取可变参数数量
print("arg num : " .. num)
local ret
if num == 0 then
print("main logic return true.")
ret = true
else
print("main logic return false.")
ret = false
end
return ret, #arg --返回两个结果,一个是布尔型变量ret,一个是可变参数数量#arg
end
接下来,写一段C++程序,来调用以上两个Lua函数。
#include <iostream>
#include <stdlib.h>
#include <string>
#include <vector>
#include "lua.hpp"
using namespace std;
/* 初始化函数 */
lua_State* script_initialize(const char* script_name)
{
lua_State *pLua = luaL_newstate(); //创建一个Lua虚拟机
if(!pLua)
{
cout << "Failed to open Lua!" << endl;
return NULL;
}
luaL_openlibs(pLua); //将标准类库加载到Lua虚拟机
luaL_dofile(pLua, script_name); //加载并运行lua文件
return pLua;
}
int main()
{
int ret = -1;
int param_num = 0;
double in_param = 50;
vector<string> objects;
objects.push_back("car");
objects.push_back("human");
objects.push_back("dog");
/* 创建并初始化Lua状态机,要调用的Lua函数位于script.lua中 */
lua_State *pL = script_initialize("script.lua");
if(!pL)
{
cout << "Script initialized failed!" << endl;
return -1;
}
cout << "Script initialized successed!" << endl;
/* ----------------------Stage I------------------------------------ */
/* Get lua function */
lua_getglobal(pL, "first_check");
/* call lua function 1 */
if(lua_isfunction(pL, -1))
{
/* Push parameters to lua stack */
lua_pushnumber(pL, in_param);
lua_pushstring(pL, "");
param_num = 2;
ret = lua_pcall(pL, param_num, LUA_MULTRET, 0); //调用Lua函数first_check,LUA_MULTRET允许所有的返回值都被压入栈
if(ret != 0)
{
cout << "lua_pcall failed!" << endl;
return -1;
}
bool b_next = lua_toboolean(pL, -1); //由于只有一个返回值,直接从栈底取结果
if(!b_next)
{
cout << "Do not need next step, will return." << endl;
cout << "lua_gettop() = " << lua_gettop(pL) << endl;
/* Pop the first function result */
lua_pop(pL, 1);
return 0;
}
cout << "Need next step, will go on." << endl;
}
cout << "lua_gettop() = " << lua_gettop(pL) << endl;
/* Pop the first function result */
lua_pop(pL, 1); //将函数first_check()的结果出栈,将栈清空
/* ----------------------Stage II-------------------------------------- */
/* Next function */
lua_getglobal(pL, "main_logic"); // 第二个函数main_logic()入栈
/* call lua function 2 */
if(lua_isfunction(pL, -1))
{
lua_pushnumber(pL, in_param); // 将第二个函数的固定参数压入栈
lua_pushstring(pL, "");
param_num = 2;
for(int i = 0; i < objects.size(); i++) //将第二个函数的可变参数压入栈,同时记录压入栈的总个数param_num
{
lua_pushstring(pL, objects[i].c_str());
param_num++;
}
ret = lua_pcall(pL, param_num, LUA_MULTRET, 0); //调用函数main_logic()
if(ret != 0)
{
cout << "lua_pcall failed!" << endl;
return -1;
}
/* 通过lua_gettop()获取栈里函数返回结果的个数 */
int ret_num = lua_gettop(pL);
if(ret_num == 2)
{
/* Get output result from stack top */
int out_rslt_1 = lua_tonumber(pL, -1); // 栈顶:返回的第二个值在栈顶
bool out_rslt_2 = lua_toboolean(pL, -2); // 栈底:返回的第一个值先压栈,在栈底;
cout << "Output result 1 is " << out_rslt_1 << endl;
cout << "Output result 2 is " << out_rslt_2 << endl;
}
else if(ret_num == 1)
{
bool out_rslt = lua_toboolean(pL, -1);
cout << "Output result 1 is " << out_rslt << endl;
}
cout << "---1---lua_gettop(): " << lua_gettop(pL) << endl;
while(lua_gettop(pL) != 0)
{
lua_pop(pL, -1);
}
cout << "---2---lua_gettop(): " << lua_gettop(pL) << endl;
}
/* Release lua state */
lua_close(pL);
}
执行结果:
3. 补充
在以上例子中,我们通过arg={...}以及#arg来获取可变参数的数量,也可以通过select("#",...) 来获取可变参数的数量。select()的用法如下:
do
function foo(...)
for i = 1, select('#', ...) do -->获取参数总数
local arg = select(i, ...); -->读取参数
print("arg", arg);
end
end
foo(1, 2, 3, 4);
end
执行结果:
arg 1 arg 2 arg 3 arg 4