function
一般概念 :
MudOS 有一种称为 function (函数指针) 的变量类型. 这种类型的变量可以用来指向各种不同的函数.
您也许早已熟悉把一个函数当作某些外部函数 (efuns) 参数. 举例来说, 像是过滤数组的外部函数.
它读入一个数组, 并经由一个函数过滤数组中的元素. 让此函数返回非零值 (non-zero)
的元素就保留下来, 结果返回一个新的数组. 传统上, 这样做要传入一个物件和函数的名称.
现在, 可以用函数指针这种变量类型做到. 函数指针只含有一个函数的信息, 可以在稍后执行其函数.
函数指针可以创造并指定为变量:
function f = (: local_func :);
上面的 f 可以用于其他程序流程或外部函数中, 如同普通的变量值:
foo(f); map_array( ({ 1, 2 }), f);
或是稍后再执行 f:
上一行执行时, 会调用 f 指向的函数, 而 "hi" 当成参数传入函数. 其效果同下:
使用函数指针的好处是, 如果您想使用不同的函数, 只需要改变函数指针变量的值.
注意 evaluate() 的参数如果不是函数, 就只会返回参数值. 所以您可以做以下的
事:
void set_short(mixed x) { short = x; }
mixed query_short() { return evaluate(short);
}
这样, 简单的物件可以只用 set_short("Whatever"); 以达成
set_short( (: short_func :) ); 的效果.
目前函数指针的种类 :
最简单的函数指针如上面所述. 只是简单地指向同一个物件中的一个局部函数
(local function), 即 (: function_name :). 函数指针的值可以包括函数的参数,
例如:
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 :). 这样与局部函数指针很类似.
譬如说, objects() 外部函数要传入函数, 并返回任何使函数为真值的物件. 所以:
会返回游戏中所有的复制物件 (clones). 您也可以使用参数:
就会印出:
Hello, world!
Hello, world!
Hello, world!
注意, 对函数指针来说, simul_efuns (模拟外部函数) 与外部函数是相同的.
第三种形式是 call_other 函数指针, 与以前 MudOS 所使用的函数指针类型类似.
其形式为 (: 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" })
:)
以下是达到同样目的的做法参考:
f = (: call_other, this_player(), "query", "short"
:) /* 一个外部函数指针, 使用 call_other */
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];
第五种形式是不知名 (anonymous) 函数:
会印出: 1 3 -2
注意, (*f)(...) 等于 evaluate(f, ...) , 保留这种语法是为了与旧版相容.
任何普通函数合法 (legal) 的写法, 都可以用于不知名函数.
什么时候执行 (evaluate) 函数 ?
创造带有参数的外部函数、局部函数、模拟外部函数指针时, 会执行函数. 而运算式和功能性
(functional) 函数指针, 只有在使用函数指针时执行函数:
(: destruct, this_player() :) /*
创造这个函数指针时, 就会摧毁 this_player(). 函数于创造时执行. */
(: destruct(this_player()) :) /*
在稍后使用此函数指针时, 才会摧毁 this_player()" */
在此, 不可以在运算式函数指针里, 使用一个局部变量. 因为执行这个函数指针之后,
这个局部变量就不存在了. 但是可以用下面这个方法解决:
(: destruct( $(this_player) ) :)
// 与上面第一个范例相同.
$(whatever) 表示要执行 whatever, 并保留其值. 当执行此函数时, 再传入这个值.
这样一来可以更有效率:
map_array(listeners,
(: tell_object($1, $(this_player()->query_name())
+ " bows.\n") :) );
只做一次 call_other , 而不需要每个消息都做. 也可以事先合并字符串:
map_array(listeners,
(: tell_object($1, $(this_player()->query_name()
+ " bows.\n")) :) );
注意, 在这个情形下, 也可以这样做:
map_array(listeners,
(: tell_object, this_player()->query_name() +
" bows.\n" :) );
翻译: Spock @ FF 97.Aug.10.
回到上一页