发信人: jinna@phoenix (吉娜), 信区: mud
标  题: lpc (3) -- 自由软体
发信站: 交大资工凤凰城资讯站 (Fri May 24 20:04:57 1996)
转信站: phoenix
Origin: sleepy.ice.ntnu.edu.tw

                        LPC Basics
                Written by Descrates of Borg
                        23 April 1993
                     Translated by Hanzo

                第三章  函数 (Functions)

          现在，你知道物件 (objects) 是由函数所组成。物件与游戏的
        其他部份以呼叫函数 (call function) 的方式互动。你也知道变
        数 (Variables) 与其最基本的三种LPC资料型态 void, int 与
        string。若你不完全了解这些，你需要复习第一章和第二章。

          LPC 的函数就像数学的函数一样，需要输入值与输出计算结果。
        有些语言像 Pascal 的程序 (procedure) 和函数 (function)的构

        想 (concept)是不同的，但是在 LPC 中是没有分别的。在 Pascal
        中称为程序 (procedure)，在 LPC 中称为 type void 的函数 (a
        function of type void)。这是指一个函数不会输出一的有用的值。
        最平常的函数像以下的例子:

        void do_nothing() { }

        这个函数没有输入值，不执行指令，也没有输出任何有效值。


        有效的函数必须包含三个部份:

        (1) 宣告 (the declaration)
        (2) 定义 (the definition)
        (3) 呼叫 (the call)

        函数与变数相同，都必须做宣告 (declare)。宣告可以使驱动程式知
        道几件事: (1)此函数将会传回 (return) 何种函数资料。 (2)有几
        个输入值以及它们的种类。
        更为常用的函数输入值称为"参数" (parameter) 。而从现在起，所
        有的函数输入值将被称为函数之参数。

        定义 (definition) 是一个能告诉驱动程式这个被定义的函数将如何
        处理它的输入值的代号。

        呼叫 (call) 是从别的程式输入一个代号来使用一个已定义的完整函
        数。

        以下是一个函数的例子:

        void write_vals();       /* 这通常是宣告 */
        int add(int x, int y);   /* 开始输入物件的代号 */

        void write_vals() {      /* 这个函数的定义 */
            int x;               /* write_vals().  写入 x 的值 */

            x = add(2, 2);       /* 呼叫 add(). 送出 add() 函数所
                                        需的输入值 */
            write(x+"\n");       /* 传回变数 x 的值 */
        }

        int add(int x, int y) {  /* add() 的定义，需要两个整数输
                                        入值 */
            return x + y;        /* 把执行的结果传回呼叫此函数的
                                        函数 */
        }

        函数呼叫的顺序和代号的排列顺并不需要一致，但是函数的宣告必
        须放在此函数的定义之前而且必须放在每一个呼叫此函数的函数之
        前。

        现在你应该成功的了解一个函数的组成结构了。了解你要呼叫的函
        数的传回资料的种类是十分重要的。如果你把一个函数的传回的文
        字资料指定到一个并宣告为整数的变数，最后得到的一定是错误的
        执行结果。你曾注意到一些你以前看不懂的代号是函数吗？例如:
        this_player(), write(), say(), this_object() 等.
        事实上，在上面提到的 write_val() 函数中，包函两个"呼叫"。
        第一个是由你自己定义的 add() 。第二的是由驱动程式定义的
        write()。驱动程式 (driver)已经替你将 write() 宣告和定义完
        毕。你只须要呼叫它出来用即可。此类的函数称为 efuns，efuns
        是 everywhere function 的缩写。efuns 定义在游戏驱动程式的
        C 之中。因为如此，所以呼叫 efuns 比呼叫设计者自行创造的函
        数要快一些，而且呼叫的方式计完全相同。但在使用 efuns 之前
        必须注意两件事:
        (1)efuns 函数的传回资料的种类 (2)efuns 函数所需要的参数。
        大部份的 mud都会有以下的其中之一:
          最常见: 在叫做 /doc/efun 的子目录中。在其中宣告和描述放
        在此目录中的 efuns。
          此外: 一个叫 man 或 help 的指令可供使用。若你键入 man
        write 或 help write，就可以得到在 /doc/efun 中的资料。
        你可以看到 write() 函数如下:

        void write(string|int)

        这表示一个正确的呼叫 write() 没有传回资料，而需要一个字串
        或是整数当作输入值。

        在函数中，定义的说明放置的顺序是非常重要的。例如在以上的
        write_vals() 的函数中，若想得到正确的 write() 输出值，那个
        把 add() 传回资料指定到 x 的说明必须放在呼叫 write() 的说
        明之前。换而言之，虽然函数可以不同置于档案之中。但是在函数
        的定义中，定义的说明必须按照它们被执行的先后顺序放置。

        最后还有一点补充是有关于传回资料的。把资料传回到一个函数的
        简单方法是在欲执行的函数中加入此说明:
                return value;
        其中的 value 是指一个能够符合此函数宣告之任何型态的变数或
        常数。

        总结:
        LPC 的物件档案是由许多函数所组成。而函数是由三部份组成: (1)
        宣告 (2) 定义 (3) 呼叫。函数的定义可以用任何方式出现在物件档
        案之中除了你不能把这个函数定义在别的函数之中。函数的宣告必须
        出现在函数的定义和任何对此函数的呼叫之前。每次需要用到一个函
        数之时，可用呼叫的方式来执行那个函数。函数的定义是由一系列有
        顺序的代号 (code) 所组成，顺序如下:
        (1) 函数的送回资料型态。
        (2) 函数的名字。
        (3) 参数列。
        (4) 一个开始的符号 "{" 表示所有的指令从此符号之后开始。
        (5) 说明、表示和呼叫其他的函数。
        (6) 一个结束的符号 "}" 表示所有的指令从此符号之后结束。

        以下是一个简单而完整的函数的例子:
        void do_nothing() { }
        说明 (instruction) : 指示驱动程式要做的事。
        表示 (expression)  : 有关于数值的说明，像 "a==b"
        呼叫 (call)        : 所有的函数呼叫的顺序必须符合你所要执行
                             的顺序。

        每一个游戏的驱动程式中，都有一些预先设定好的函数称为 efuns。
        你可以在大部份的 mud 的 /doc/efun 目录中找到详细资料。有的
        mud 站有特别的巫师 help 或 man 指令供线上查询使用。使用这些
        efuns 必须遵守已经被定义在 efuns 中的方式。例如参数的数量和
        形态或传回资料的形态等等。

        注意:
        有的 mud 驱动程式不要求作函数的宣告。有些甚至不需要你指定函
        数的传回资料形态。但不论如何，想要省略宣告或传回资料形态的定
        义是不明智的。因为:
        (1) 方便别人(包括你自己在内)读你写的函数。
        (2) 容易找到在你的程式中，有由于资料形态不符造成的错误。
        (3) 这是公认的一种好的函数写作方式。

        另外，efuns 在各个驱动程式中的设定大致相同。另外，还有类似的
        函数群称为 simul efuns (simulated efuns)。simul efuns 就会随
        着 mudlib 的不同而不同。simul efuns 是被定义在 LPC 中的特殊物
        件称为 simul_efun.c 的档案中。每个好的 mudlib 对其 simul_funs
        都会有充份的说明文件。有的 mud 会将部份的 efuns 从驱动程式中
        搬到 mudlib 中而变成 simul_efuns。但对一个程式设计者而言并没
        有差异。我之所以特别指出这点是因为有的人在他 mud 站的 efun
        中找不到 write() 而是在 simul_efun 之中。若一切正常，write()
        在大部份的 mud 中将是一个 simul_efun。
--
  本份文件来自 wade@Fantasy.Space
  在遵守自由软体宣言的条件下, 您可以自由使用本文件

  本文件内容如有错漏, 请各位不吝指正



