第三章 Lpc的函数 第一节 序言 在前面的介绍中,大家应该知道了Lpc的Object包含能处理变量的函数。 当函数被执行时,它的工作就是处理操作变量,还有是调用(call)别的函 数。变量在函数中被改变操作。变量必须有个数据类型使得计算机能明白 它指向的内存中"0"和"1"到底是什么东西。一个Object的性质通常由它的 包含的变量确定,但是它的特性的表现却是依赖于它包含的函数。一个 Object如果不含有任何一个函数那是不可想象的。那么:什么是函数。 第二节 函数 2.1 什么是函数? 和数学的函数一样,你给Lpc的函数一个值,它能返回一个值。有些语 言,比如Pascal,会区分过程和函数。Lpc和C/C++一样,没有过程,但是 明白这种区别还是有用的。Pascal叫做过程的东西,Lpc叫做类型是void 的函数。换句话说,过程就是什么都不返回的函数。Pascal叫做函数的, 必须返回一些东西。在Lpc中,最无聊的,最简单的,但也是正确的函数 是这样的: ----- void eventDoNothing() {} ----- 这个函数不接收任何输入,不执行指令,也不返回任何值。 每一个Lpc函数都由三部分组成: 1) 函数声明 2) 函数定义 3) 函数调用 和变量一样,函数必须先有个声明。这样可以让Driver知道: 1) 这个函数将返回的是哪种数据类型。 2) 需要的输入是什么,多少。通常把输入叫做参数。 一个函数声明通常是这样的: 类型 函数名(参数1, 参数2, ..., 参数N); 下面是一个函数声明的例子,这个函数叫 DrinkWater,有一个string 类型的参数,返回的是一个int。 ----- int eventDrinkWater(string str); ----- 在上面的声明中, str是输入的参数的变量名,也可以没有。就是说可以 象下面这样声明 eventDrinkWater() ----- int eventDrinkWater(string); ----- 函数定义就是代码,它描述了这个函数对传人的参数究竟做了些什么。 函数调用就是别的函数在任何地方使用执行了这个函数。一个函数在它 写完后永远不会被调用,那这个函数的存在的唯一意义只能是浪费内存和 硬盘。一个函数写出来的目的是为了被调用。 下面是两个函数相互调用的例子,两个函数是 eventPrintValue() 和 add(), ----- /* 首先是函数声明,这个通常是在一个Object的开始部分。 */ void eventPrintValue(); int add(int x, int y); /* 其次是函数 write_vals() 的函数定义。我们假定这个函数将被调用 * 是为了描述这个Object. */ void eventPrintValue() { int x; x = add(2, 2); // 我们指定 x 接收调用函数 add() 后返回的值。 write(x + "\n"); } /* 最后是函数 add() 的函数定义。 */ int add(int x, int y) { return (x + y); } ----- 有一点是指明的,在XO的编程的风格我们要求所有的函数都必须有声 明,这个在我们最开始时候说明过。但是实际上必须有函数声明的函数 是那些被调用在函数定义之前的函数。我们规定必须有函数声明,这个 只是规定,但是它会给编程带来好处。 在这一节我们知道什么是函数,函数是由什么组成。要记住,写一个 函数的根本目的是为用它,调用它。一个函数永远不会被调用,那它就 失去了存在的价值。通常别人使用你写的函数,通常只关心它能对传人 的参数做些什么加工,就是这个函数的功能是什么,返回什么。因此一 个函数有一个好的函数名,能直接描述这个函数的功能是很重要的。我 在第一章中说明了XO规定的对函数的命名机制。采用统一的命名方式有 助于相互合作提高效率。 2.2 Efuns 也许你已经听说过efun这个词了,他们是外部定义的函数,是 externally defined function 的缩写。就是说,他们是由Mud Driver 定义好的。如果参加过Lpc的编程,或者看过Lpc的代码,你可能找到这 样的一些表达式:this_player(), strcmp(), implode(), filter(), 等等,看起来象是一个函数,而你找遍整个Object以及这个Object继承 的所有Object中都没有这些函数,这就表明他们是efun。efun存在价值 是因为他们执行起来要比一般的Object带有的函数速度快的多,为什么 快呢,因为他们是以计算机直接能理解的二进制的形式存在。对于Object 内部定义的函数,我们通常叫他们是lfun(local function)。一个巫师 主要工作也就是编写一些lfun组成的Object。 在上面的例子中的 eventPrintValue() 中调用了两个函数,第一个是 函数 add(), 这个是有你声明和定义的,这个就是lfun。第二次调用, 是调用函数 write() 这个函数通常就是efun。Driver已经替你声明和定 义好了。你所要做只是调用它。 efun被创立是为了 1) 处理一些很常用的,每天都有许多函数会调用的。 2) 处理internet socket的输入输出。 3) 以及一些Lpc很难处理的事,毕竟Lpc是C的很小的子集。 efun是用C写好的,内嵌在Driver里面的。在Mud起来之前,和Driver 一起编译好的,他们执行起来会快的多。但是正和你期望的一样,他们 的调用和你写的函数的调用方法是完全一样的。总的来说,需要关心的 和一般函数一样,它需要传入什么参数,它将会返回什么的东西。 怎样得到一些efun的信息,比如传入参数和返回的类型,通常在一个 Mud里面,你可以在类似这样的 /doc/efun 的目录底下找到,或者直接 用 help 指令就可以得到帮助。efun及其依赖于你所在的Mud 的Driver,不同的Driver带有的efun区别是很大。 对于XO,使用的是MudOS,一般的efun,只要用 help 指令就能得到 帮助,或者你多看看源码,看看别人是怎样使用的,当然你如果无论如 何也不能明白一个efun,你可以问问大巫师,他们通常会很乐意和你探 讨的。但是有一点是指出,能自己解决的问题最好自己解决。