![]() |
![]() |
#1 |
高级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 08年04月11日
来自: 盘丝洞
帖子: 311
声望力: 20
声望:
50
![]() 现金:29两梁山币
资产:1245两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
LPC帮助文档—变量类型—函数
作者:jjgod 发表时间:2001年8月4日 10:39 -------------------------------------------------------------------------------- 一篇偶翻译的文档,请指正。 LPC帮助文档—变量类型—函数 基本概念: MudOS 有一个叫做“function”的变量类型,这种变量可以 用于指向一种普遍的函数。你可能已经熟悉传递一个函数到 某个 efun 的主意。拿取,比如说 filter_array这个efun, 它获取一个数祖,然后返回一个其每个元素都在某个函数中 返回非零的数组。习惯上,这个过程是由传递一个物件和一 个函数的名称来完成的。现在呢,它还可以由传递一个函数 型的表达式来完成,这个表达式只是包括了了一个可以稍后 进行计算的函数。 函数指针可以被创建和分派到一个变量,例如: function f = (: local_func :); 以及被传递到其他的常规情况或者 efuns,就像普通的值一 样: foo(f); map_array( ({ 1, 2 }), f); 或者在稍后进行计算: x = evaluate(f, "hi"); 当最后一行被运行后,f 指出的这个函数就被呼叫了,而“ hi”则被作为一个实参。这样做将达到与下面同样的效果: x = local_func("hi"); 使用一个函数指针的优势是:如果此后你想运行的是另一个 函数,你可以仅仅改变变量的值就行了。 值得注意的是,如果 evaluate() 被输入一个不是函数的值, 它将原封不动的把这个值再传回来。你可以这样试试: void set_short(mixed x) { short = x; } mixed query_short() { return evaluate(short); } 这么做的话,一般的物件可以仅仅是:set_short("任意"), 而特殊些的就可以通过:set_short((: short_func :)); 来多样化的改变自己的短描述。 有用的几种函数指针: 上面这个就是一个最简单的函数指针,它们仅仅是指向同一 个物件中的一个本地函数。调用时,参数也可以包括在内, 例如: string foo(string a, string b) { return "(" + a "," + b + ")"; } void create() { function f = (: foo, "left" :); printf("%s %s\n", evaluate(f), evaluate(f, "right")); } 将会打印出:(left,0) (left,right) 第二种情况则是仅仅是像 (: efun_name :) 这样的 efun指 针。这种这本地函数指针是很相似的,例如 objects efun 可以获取一个可选的函数,返回所有通过此函数的结果是真 值的物件,因此:objects((: clonep :)) 将会返回一个包 括游戏中所有是复制品的物件。当然,也可以带上参数: void create() { int i; function f = (: write, "Hello, world!\n" :); for (i = 0; i < 3; i++) { evaluate(f); } } 将会打印出: Hello, world! Hello, world! Hello, world! 注意 simul_efun 在和函数指针的关系上是与 efun一样的。 第三种是和 MudOS 通常支持的类似的 call_other函数指针, 格式是:(: object, function :)。如果要使用参数,参数 要被假如一个在函数名前面的数组中。下面是例子: void create() { string *ret; function f = (: this_player(), "query" :); ret = map(({ "name", "short", "long" }), f); write(implode(ret, "\n")); } 这样将会打印出 this_player()->query("name")、 this_player()->query("short") 和 this_player()->query("long") 的结果。 要使一个函数指针直接呼叫 query("short"),可以使用: f = (: this_player(), ({ "query", "short" }) :) 下面是其他的一些同样效果的方法提供参考: // 使用 call_other efun 的 efun 指针 f = (: call_other, this_player(), "query", "short" :) // 一个表达式的功能,看看下边 f = (: this_player()->query("short") :) 第四种则是表达式函数指针。这是以 (: expression :) 的 形式来使用的。在一个表达式函数指针中,参数可以写成类 似于 $1、$2、$3...这样的形式,例如: evaluate((: $1 + $2 :), 3, 4) // 返回 7. 在用到 sort_array 时,它将很有用,例如: top_ten = sort_array(player_list, (: $2->query_level() - $1->query_level :) )[0..9]; 第五种可以称为无名的函数指针: void create() { function f = function(int x) { int y; switch(x) { case 1: y = 3; case 2: y = 5; } return y - 2; }; printf("%i %i %i\n", (*f)(1), (*f)(2), (*f)(3)); } 将会打印出:1 3 -2 注意那个 (*f)(...) 是和 evaluate(f, ...)一样而且被保 留作向后兼容。凡是在一般函数中合法的东西在无名函数中 就是合法的。 函数将在什么时候被运行呢? 有一条原则是:在 efun、本地函数和 simul_efun函数指针 被创建时,作为其参数的函数就被运行了。如果是一个表达 式形式的函数指针,则是要等到此函数指针确实地被使用时 才运行: // 当此函数指针创建时它就将 destruct 所有是 // this_player() 的人 (: destruct, this_player() :) // 当此函数运行时才 destruct 所有是 this_player() // 的人 (: destruct(this_player()) :) 因此,在一个表达式指针中,使用一个本地变量是违法的。 因为等到这个函数指针运行的时候,可能这个变量已经不存 在了。然而,还是有一种解决的方法: // 和上面的第一个例子一样 (: destruct($(this_player)) :) $(whatever) 的意思就是立即计算whatever,保持着这个值, 直到这个函数被运行的时候再拿出来用。这还可以使事情做 得更有效率: map_array(listeners, (: tell_object($1, $(this_player()->query_name()) + " bows.\n") :)); 上面的这个 $(this_player()->query_name()) 只需要被计 算一次,而不是每次消息时都再计算一次。当然增加的那段 也可以预先做好: map_array(listeners, (: tell_object($1, $(this_player()->query_name() + " bows.\n")) :)); 注意,在这种情况下我们也可以这样做(效率最低的方式): map_array(listeners, (: tell_object, this_player()->query_name() + " bows.\n" :)); 翻译使用的词汇: evaluate : 运行、计算 function pointer : 函数指针 argument : 参数 local : 本地 variable : 变量 whatever : 任意 -------------------------------------------------------------------------------- 莫愁前路无知己,天下谁人不识君? 原文 作者:jjgod 发表时间:2001年8月4日 10:42 -------------------------------------------------------------------------------- General Concept: ---------------- MudOS has a variable type named 'function'. Variables of this type may be used to point to a wide variety of functions. You are probably already familiar with the idea of passing a function to certain efuns. Take, for example, the filter efun. It takes an array, and returns an array containing the elements for which a certain function returns non-zero. Traditionally, this was done by passing an object and a function name. Now, it can also be done by passing an expression of type 'function' which merely contains information about a function, which can be evaluated later. Function pointers can be created and assigned to variables: function f = (: local_func :); Passed to other routines or efuns, just like normal values: foo(f); map_array( ({ 1, 2 }), f); Or evaluated at a later time: x = evaluate(f, "hi"); When the last line is run, the function that f points to is called, and "hi" is passed to it. This will create the same effect as if you had done: x = local_func("hi"); The advantage of using a function pointer is that if you later want to use a different function, you can just change the value of the variable. Note that if evaluate() is passed a value that is not a function, it just returns the value. So you can do something like: void set_short(mixed x) { short = x; } mixed query_short() { return evaluate(short); } This way, simple objects can simply do: set_short("Whatever"), while objects that want their shorts to change can do: set_short( (: short_func :) ); Available kinds of function pointers: ------------------------------------- The simplest function pointers are the ones shown above. These simply point to a local function in the same object, and are made using (: function_name :). Arguments can also be included; for example: string foo(string a, string b) { return "(" + a "," + b + ")"; } void create() { function f = (: foo, "left" :); printf( "%s %s\n", evaluate(f), evaluate(f, "right") ); } Will print: (left,0) (left,right) The second kind is the efun pointer, which is just (: efun_name :). This is very similar to the local function pointer. For example, the objects() efun takes a optional function, and returns all objects for which the function is true, so: objects( (: clonep :) ) will return an array of all the objects in the game which are clones. Arguments can also be used: void create() { int i; function f = (: write, "Hello, world!\n" :); for (i=0; i<3; i++) { evaluate(f); } } Will print: Hello, world! Hello, world! Hello, world! Note that simul_efuns work exactly like efuns with respect to function pointers. The third type is the call_other function pointer, which is similar to the type of function pointer MudOS used to support. The form is (: object, function :). If arguments are to be used, the should be added to an array along with the function name. Here are some examples: void create() { string *ret; function f = (: this_player(), "query" :); ret = map( ({ "name", "short", "long" }), f ); write(implode(ret, "\n")); } This would print the results of this_player()->query("name"), this_player()->query("short"), and this_player()->query("long"). To make a function pointer that calls query("short") directly, use: f = (: this_player(), ({ "query", "short" }) :) For reference, here are some other ways of doing the same thing: f = (: call_other, this_player(), "query", "short" :) // a efun pointer using // the call_other efun f = (: this_player()->query("short") :) // an expression functional; see // below. The fourth type is the expression function pointer. It is made using (: expression :). Within an expression function pointer, the arguments to it can be refered to as $1, $2, $3 ..., for example: evaluate( (: $1 + $2 :), 3, 4) // returns 7. This can be very useful for using sort_array, for example: top_ten = sort_array( player_list, (: $2->query_level() - $1->query_level :) )[0..9]; The fifth type is an anonymous function: void create() { function f = function(int x) { int y; switch(x) { case 1: y = 3; case 2: y = 5; } return y - 2; }; printf("%i %i %i\n", (*f)(1), (*f)(2), (*f)(3)); } would print: 1 3 -2 Note that (*f)(...) is the same as evaluate(f, ...) and is retained for backwards compatibility. Anything that is legal in a normal function is legal in an anonymous function. When are things evaluated? -------------------------- The rule is that arguments included in the creation of efun, local function, and simul_efun function pointers are evaluated when the function pointer is made. For expression and functional function pointers, nothing is evaluated until the function pointer is actually used: (: destruct, this_player() :) // When it is *evaluated*, it will destruct // whoever "this_player()" was when it // was *made* (: destruct(this_player()) :) // destructs whoever is "this_player()" // when the function is *evaluated* For this reason, it is illegal to use a local variable in an expression pointer, since the local variable may no longer exist when the function pointer is evaluated. However, there is a way around it: (: destruct( $(this_player) ) :) // Same as the first example above $(whatever) means 'evaluate whatever, and hold it's value, inserting it when the function is evaluated'. It also can be used to make things more efficient: map_array(listeners, (: tell_object($1, $(this_player()->query_name()) + " bows.\n") :) ); only does one call_other, instead of one for every message. The string addition could also be done before hand: map_array(listeners, (: tell_object($1, $(this_player()->query_name() + " bows.\n")) :) ); Notice, in this case we could also do: map_array(listeners, (: tell_object, this_player()->query_name() + " bows.\n" :) ); |
![]() |
![]() |
![]() ![]() |
添加到书签 |
|
|
![]() |
||||
主题 | 主题作者 | 论坛 | 回复 | 最后发表 |
zmud内键常用函数集 | Odysseus | 『 机器人制作及下载 』 | 3 | 2016-03-19 13:50 |
zmud函数入门 | wolf_iori | 『 机器人制作及下载 』 | 6 | 2011-11-14 01:25 |
【马帮】 机器讲座(一) zmud内建函数 | argus | 『 帮派传说 』 | 12 | 2010-09-02 09:16 |
zmud函数入门 | wolf_iori | 『 机器人制作及下载 』 | 3 | 2008-05-11 19:41 |
zmud函数入门1 | wolf_iori | 『 机器人制作及下载 』 | 4 | 2008-05-11 19:38 |