使用函数参数

请参考:定义函数

形参、实参

形参:函数定义时被包含在括号中具名参数,形参名也是局部有效的变量名字。
实参:函数调用时括号中包含的实际参数,实际参数是一个右值表达式。

//这里的a,b,c称为形参,可以将形参看成函数内部的局部变量名字
function
test(a,b,c){ return a+b+c; //形参可以在函数体内部作为局部变量使用 }
返回值= test(2,3,4); //这里的2,3,4 称为实参

实参的数目如果多于形参的数目,多余部分被丢弃。
实参的数目如果少于形参的个数,不足的部分添加null值。

请参考:调用函数

可变参数

1、在形参列表尾部定义可变参数

在定数定义的形参列表尾部,可以用三个连续的圆点表示可变参数(不定参数)。
可变参数必须是最后一个参数,如下:

io.open() 

func = function( a,b, ... ){ //使用三个连续的圆点表示任意个数、任意类型的参数
	var arg = { ... }
	io.print( #arg + "个参数", arg[1],arg[2] )
}

func(1,2,99,888,777);


2、在实参列表尾部使用可变参数

在实参列表尾部可以使用可变参数

io.open()

str ="abcd"

//在实参尾部可以使用不定参数
io.print( "string.unpack有多个返回值",string.unpack(str) );

//可变参数不放在最后面就只能取第一个值
io.print( string.unpack(str) ,"string.unpack的第一个返回值");

 

在形参中指定默认值参数

实参可以省略,省略的实参传递null空值。如下:

io.open(); //打开控制台

io.print( , ,2,3,) //下面都是等价的写法
io.print( null , null , 2 , 3 , null ) //与上面一行的作用相同
io.print( null , null , 2 , 3  ) //与上面一行的作用类似

在函数定义的形参表中,可以为任意参数指定默认值.
如果省略相应实参,或实参为null值时,如果参数指定了默认值,则将默认值作为实参。

在其他一些编程语言中,只能为尾部的参数的指定默认参数,而在aardio中你可以打破这一局限,为任意的形参指定默认参数。

示例如下:
io.open(); //打开控制台窗口

//在函数定义的形参中,使用等号指定形参的默认值;
function func(a,b=123,c="字符串",d=2,e=true) {
	io.print(a,b,c,d,e)
}

//调用函数
func(1,,,4,5 )


形参默认值仅允许使用以上示例中演示的字面值常量(数值、字符串、布尔值),不可使用其他变量或表达式。

在函数实参中构造表

当函数的所有实参由键值对组成,并由分号分隔,aardio将实参构造为table对象。

示例:

//打开控制台窗口 
io.open();

function func(tab,a,b){ 
	io.print(tab,a,b); 
}


//此时 形参tab= 1, 形参a= 2, 形参b=3
func(  1,2,3);

//aardio将下面这句代码解析为 func(  { k=1 ; k2 = 2 } )
func( k=1 ; k2 = 2  );

构造表作为函数参数,可以增强代码的可读性。例如:

  函数调用  ( 
    名字 =   "某某"; 
    住址 =   "北京"; 
    家庭成员 =  统计函数( 
				男 = 6, 
				女 = 3, 
				老 = 1, 
				幼 = 1, 
				) 
  );


table参数的副作用

1、纯函数

在aardio中函数是纯函数(Pure Function)- 输入输出数据流都是显式(Explicit)的。
函数从函数外部接受的所有输入信息都通过参数传递到该函数内部;函数输出到函数外部的所有信息都通过返回值传递到该函数外部,即函数的数据只有一个入口( 参数 ),一个出口( 返回值 )。函数可以返回多个值。

aardio的函数只有输入参数,没有输出参数,不能在函数体中改变实参的数据。
API函数中的输出参数同样被转换为返回值 - 然后附加到返回值列表中。

2、具有副作用的table参数

在虚函数中传址参数仍然具有副作用,table对象在赋值或传参中都是传址的,传递过程中并不改变指向的对象,而table的成员又是可修改的,这就使table对象在函数的传参过程中具有副作用,对table参数的成员进行修改会作用到外部对象,修改的作用域不局限于函数体内部。

如果需要在函数内部改变外部变量的值,那么应当把数据封装到一个table对象中。

function set(t) { //table参数具有副作用 
    t.x = 256; //在这里可以改变table参数对象的成员值,并作用到函数外部
 
    //t不是输出参数,下面的代码仍然不能改变外部table对象
    t = 123;//请注意输出参数针对的是参数本身,而副作用影响的是参数指向的数据
}

tab ={x=10,y=20}
set(tab); //table参数是按引用传递的

io.open(); //打开控制台窗口
io.print(tab.x); //显示256,tab.x被函数改变了 

这个有一点利用潜规则走后门的意思,不声不响的修改了外部的对象,又没有显式的交待,应当尽量避免这么做。当然,没有必要默守成规,可以使用更友好的函数命名,清晰的注明副作用。例如:

import win;
point = ::POINT(12,23);

::ClientToScreen(hwnd,point);//ClientToScreen的函数清晰的注明了它会改变point中的坐标

result,point = ::ClientToScreen(hwnd,point);//这是更推荐的写法

有经验的程序员总是不断提醒我们,多打几个字,减少大堆的麻烦!

输出参数

虽然从语法上说,aardio函数没有定义输出参数的这个概念,但是aardio函数支持在函数中返回多个返回值,通过返回值也可以实现修改输出参数的值,举个例子:

test = function(x,y){
	x = x + 1;
	y = y + 1;
	return x,y;
}

var x,y = 1,2;

//这里输入参数是 x,y,通过返回值接收了x,y的新值
x,y = test(x,y);

aardio 在调用外部 COM 函数,或者外部 API 函数时,同样是使用上面的方法来支持输出参数。
例如调用COM函数时,所有输出参数都会增加一个返回值(按参数的前后位置排序返回),而调用外部API函数时,是同样的,所以在API函数声明中定义为输出参数的参数(类型后面加&,例如int &) - 都会增加一个对应的返回值。

如果在 aardio中定义外部COM函数或外部API函数需要用到的回调函数时,同样使用多个返回值来修改输出参数的值。


例如,在调用API函数时定义stdcall回调函数,下面的x就是输出参数:
stdCallback = raw.tostdcall( 
	function(x){
		x = x + 1; 
		return 123,x;
	},"int(int &x)"
)


或者在调用COM控件时定义各种回调函数(例如定义 COM事件),例如在使用web.form时定义NewWindow3事件:
wb.NewWindow3 = function(ppDisp,cancel,dwFlags,bstrUrlContext,bstrUrl ) { 
 
    //这里ppDisp,cancel都是输出参数,下面修改了cancel的值为true
    return ppDisp,true;
};

owner参数

请参考:owner