第五章 变量控制和流程控制 第一节 序言 到今天,你应该能自己编写一些简单的 Object 了,通过使用你所在 的 Mud 的标准的 Object 库。 你应该知道什么是继承了,还有你应该 能自己写一些函数来表现你自己的 Object 特有的性质了。在这一章, 你将知道 Lpc 的最基本的一些元素,比如:表达式、操作符等,在你 自己写的函数通过一些基本元素的组合来操纵变量,通过流程控制来使 的你的函数更为复杂,而不是线性执行到最后。 第二节 变量 2.1 值和变量 从根本来说,任意两个 Object 不同的地方有两个方面: 1) 一些函数不同 2) 各个变量的值不同 举个例子,所有的玩家 Object 有完全一样的函数。因此他们不同的 只是保持的值不同。比如,玩家名字叫做 "falcon" 和 "trill" 不同, 其最根本的不同的是因为变量 "dbase/id" 这个值不同,一个是"falcon" 另一个是 "trill" 。 因此,在 Mud 中的变化就是各个 Object 中的值的变化。函数是用来 命名那些可以改变操纵变量的特殊的一些过程。举个例子,函数 create() 就是这样一个过程:初始化一个 Object 的各个变量的值的一个过程。 在函数里面,有个特别的东西叫做 指令 用于直接改变操纵变量。 2.2 局部和全局变量 和大多数的编程语言一样,Lpc 的变量可以被声明成一个函数的局部 变量,也可以是全局变量(这个全局变量只在一个 Object 内部是全局的, 对于其他 Object 的函数是不能访问的)。局部变量在一个函数定义内部 声明,只在这个函数内部使用。别的函数无法得知它的存在。全部变量 则只要所在的 Object 存在时间内,可以被这个 Obejct 声明的任何函数 调用,就是它一直在内存中存在。看看下面的两个例子: ----- int x; int GetX() { return x; } void SetX( int y ) { x = y; } ----- ----- void SetX( int y ) { int x; x = y; write( "x is set to x" + x + " and will now be forgotten.\n" ); } ----- 在第一个例子里面,x 在所有的函数的外部声明,所以它可以被它后面 的任何函数使用。在这个例子中,x 就是一个全局变量。 在第二个例子中,x 在函数 SetX() 的内部声明。它只有在函数 SetX() 被执行时才存在。然后,它就消失了。在这个例子中,x 是局部变量。 2.2 表达式和操作符 在 Lpc 中表达式和操作符的意义和 C/C++ 的完全一样,如果你在这个 方面一无所知,那就去找一本 C/C++ 的入门的书。 在本章的附录中列出 Lpc 常用的各个操作符的用法,以及 MudOS提供 的一些特别操作符。 2,3 小结 现在你应该知道在不同地方声明一个变量的区别了。我们在上面说的 全局变量和一般的 C/C++ 中的全局变量的意义不同。一般的,在 C/C++ 的全局变量在这个程序执行整个过程一直存在,但是 Lpc 的全局变量实 际是“类变量”,或者说是“Ojbect 变量”,一个 Object 的全局变量, 在 Object 存在时存在,而没有真正的永远存在的“全局变量”。通过 对操作符,变量、常量和函数的组合,你能得到一个很复杂的表达式, 比如: i = ( x = sizeof( users() ) > 0 ) ? x -- : ( ( sizeof( children( NPC ) - 1 ); 现在大家应该能知道上面的表达式的值了吧?其中 efun users() 返回 所有的玩家,children( NPC ) 返回所有 NPC 复制的 Object, sizeof()能 得知一个 array 或者 mapping 的大小。 第三节 流程控制 2.1 流程控制 在上一节的例子中: ----- void SetX( int y ) { int x; x = y; write( "x is set to x" + x + " and will now be forgotten.\n" ); } ----- 你可能只想在 y > 1 时候把这个值赋予 x。怎么办,那就是流程控制 的。流程控制,就是控制程序的执行过程。Lpc 和流程控制和 C/C++ 几乎可以说是完全一样。 2.2 流程控制语句 由于 Lpc 的流程控制实际上 C 的一样,我就不再介绍了。在本章的 附录二中,列出了 Lpc 的流程控制语句。 强调一点,switch 可以完全由 if else if else 替代,比如: switch ( id ) { case "trill" : write( "你是飞鸟。\n" ); break; case "falcon" : write( "你是狐儿。\n" ); break; case "qyz" : write( "你是小马。\n" ); break; default : write( "你是谁?\n" ); break; } 可以写成这样: if ( id == "trill" ) { write( "你是飞鸟。\n" ); } else if ( id == "falcon") { write( "你是狐儿。\n" ); } else if ( id == "qyz" ) { write( "你是小马。\n" ); } else { write("你是谁?\n"); } 但是 switch 语句更加贴近 CPU 的执行方式,也更自然。所以最好使 用 switch 语句,而不是 if else if else 的形式。 小结: 这一章介绍的实际是 C 的东西,所以如果你对于 C 语言不熟悉的话, 就找一本入门的书,看看变量,常量和流程控制的介绍。如果你对 C 有 写了解了,到现在,你应该能很容易的写一些简单的 room, npc 了。 附录一 Lpc 操作符 在这一附录,详细说明大部分的 Lpc 操作符。 Lpc 的操作符大概有下面这些: = + - * / % += -= *= /= %= -- ++ == != > < >= <= ! && || -> ? : >> << <<= >>= & | ^ &= |= ^= ... 这些操作符的说明有点枯燥无味,但是最好还是看看,因为有些操作 符的行为有些怪异。 = 赋值操作符 ( assignment operator ): 例子: x = 5; 操作值 把等号右边表达式的值赋予左边的变量。等号左边只能是 变量,就是说你不能赋予一个表达式值。 + 加号 ( addition operator ): 例子: x + 7 操作值:把加号左右的两个表达式的值(如果都是数值)加在一起, 得到一个值。如果有一个表达式的值是 string 类型的,一 个是 int 或者 float 类型,就直接把 int 和 float 的数值 变成相应的字符串,接在 string 的对应的左边或右边。如 果两个都是数组,那么就把两个数组和在一起得到一个新的 数组。 - 减号 (subtraction operator ): 例子: x - 7 操作值:这个和 + 刚好现反。 * 乘号 ( multiplication operator ): 例子: x * 7 操作值:和数学上的乘法没有什么区别。 / 除法 ( division operator ): 例子: x / 7 操作值:和数学上的除法没有什么区别。 += additive assignment operator: 例子: x += 5 操作值:如果是 a += b,那就就是 a = a + b。 -= subtraction assignment operator 例子: x -= 7 操作值:如果是 a -= b,那就就是 a = a - b。 *= multiplicative assignment operator 例子: x *= 7 操作值:如果是 a *= b,那就就是 a = a * b。 /= division assignment operator 例子: x /= 7 操作值:如果是 a /= b,那就就是 a = a / b。 ++ post/pre-increment operators 例子: i ++ or ++ i 操作值: i ++ 返回的值是 i,然后在把 i 加 1 ++ i 返回的值是 i + 1 -- post/pre-decrement operators 例子: i-- or --i 操作值: i -- 返回的值是 i -- i 返回的值是 i - 1 == equality operator != inequality operator > greater than operator < less than operator >= greater than or equal to operator <= less than or equal to operator 例子: x == y x != y x > y x < y x >= y x <= y && logical and operator || logical or operator 例子: x && y x || y ! negation operator 例子: !x -> the call other operator 例子: this_player()->GetKeyName() 操作值:调用一个 Object 的一个成员函数,左边必须是一个 Object 右边是 Object 的一个函数,如果不存在,那么就返回 0。 例子:task->event 操作值:返回一个 class 类型的变量的中的一个变量 ? : conditional operator 例子: x ? y : z 返回值:如果 x 是为真,那么就返回 y 的值,为假,就返回 z 的值 这些操作符和 C 语言的完全一样。 下面的是高颁布的 MudOS 提供的: >> << 循环右移和左移 & | ^ 按位做 与 或 异或 <<= >>= &= |= ^= 如果是 a X= b 那么就是 a = a X b 这些和 C 的也一样。 ... 返回一个数组的第一个元素。 附录二 流程控制语句: if ( 表达式 ) { 指令集 } if ( 表达式 ) { 指令集 } else { 指令集 } if( 表达式 ) { 指令集 } else if ( 表达式 ) { 指令集 } else { 指令集 } while ( 表达式 ) { 指令集 } switch ( 表达式 ) { case ( 表达式 ): 指令集; break; default: 指令集 } for( 表达式; 表达式; 表达式 ) 这些和 C 的完全一样 return 结束这次函数的执行 continue 忽略这次循环 break 跳出循环体 高颁布的 MudOS 新提供的: foreach()循环 foreach ( 变量类型 in 数组 ) 比如: void test() { foreach( object player in users() ) { tell_object( player, "hi..just a test." ); } } users() 这个 efun 返回一个 Object 的数组,所有在线的玩家。 foreach () 循环对数组中的每个元素,做一次循环。