Lua可变参数函数的使用

随着对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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值