运算符重载

对于一个table对象,我们可以重载运算符使操作数执行自定义的运算函数。

一、元方法

每个table都可以指定一个元表(metatable),在元表中可以重载运算符。
重载的操作符实际上是一个函数,称之为表的元方法

以@操作符表示元表。例如tab@表示tab的元表。
也可以在表构造器中直接用@指定元表,例如:tab={ n=123;n2=456;@{ _type = "自定义元表"} }

table的元表可以是table自已。例: tab@ = tab;

下面是使用元表重载运算符的示例:
io.open(); tab = { x=10 ; y=20 };
tab2 = { x=12 ; y=22 }
//c = tab + tab2; //这样肯定会出错,因为 table默认是不能相加的

//创建一个元素,元表中的__add函数重载加运算符。
tab@ = {
	_add = function(b) { 
		return owner.x + b.x
	};
}

c = tab + tab2; //这时候会调用重载的操作符 tab@._add(tab2)
io.print( c ) //显示22


请参考:元属性/元方法 列表

一个常见的技巧,table是按引用比较的,即使它们的值相同,但只要不是指向同一个对象都被认为是不相等,
我们通过重载==运算符可以让两个tab按它们的存储值比较。

io.open();

tab = { x=10 ; y=20 };
tab2 = { x=10 ; y=20 }
io.print( tab == tab2 ); //默认是按引用比较,不指向同一个对象就不相等,结果为false

//创建一个元素,元表中的__eq函数重载比较运算符"=="。
tab@ = {
    _eq = function( b){
        return ( (owner.x == b.x) and (owner.y == b.y) )
    };
}
tab2@ = tab@;//为tab2添加元表, 比较运算符需要为两个操作数添加同一个元表。

io.print( tab==tab2 ); //现在可以使用重载的==操作符按值比较了

避免元方法递归调用导致溢出

dic ={
	
	//创建元表
	@{ 
		_tostring = function() {
			..io.print( owner ); //递归调用了_tostring元方法,会导致堆栈溢出。
			return "aaa";
		}
	} 
	
}

io.print( dic )  //io.print会自动调用tostring(参数)

例如你有这么一个对象dic,它重载了_tostring这个元方法。
那么在调用 io.print( dic ) 时就会自动调用 io.print( tostring(dic) )
可是你在元方法里又写了..io.print( owner ) ,问题就来了,owner就是它自已,这样又要调用tostring(owner) 而这样又会调用元方法,而元方法又再次调用 tostring(owner)  这样没完没了的递归,所以就出错了。

这里只是举一个例子,类似的还有在索引元方法_get 的内部写owner["key"]
owner["key"] 又会调用 _get元方法,而_get元方法又会调用 owner["key"] 也是这样没完没了。

aardio为了避免这个问题,提供了raw操作符
而[[]] 就是一个raw操作符,它与[]不同的是,它不会调用元方法,也就是不能重载。
也就是说,在_get元方法里写 owner[["key"]] 就可以避免出现上述的递归调用错误。