一般概念 :
----------

MudOS 有一种称为 function  (函式指标) 的变数型态. 这种型态的变数可以用来
指向各种不同的函式. 您也许早已熟悉把一个函式当作某些外部函式 (efuns)  参
数. 举例来说, 像是过滤阵列的外部函式. 它读入一个阵列, 并经由一个函式过滤
阵列中的元素. 让此函式传回非零值 (non-zero) 的元素就保留下来, 结果传回一
个新的阵列. 传统上, 这样做要传入一个物件和函式的名称. 现在, 可以用函式指
标这种变数型态做到. 函数指标只含有一个函式的资讯, 可以在稍后执行其函式.

函式指标可以创造并指定为变数:

function f = (: local_func :);

上面的 f  可以用于其他程式流程或外部函式中, 如同普通的变数值:

foo(f);  map_array( ({ 1, 2 }), f);

或是稍后再执行 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("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() 外部函式要传入函式, 并传回任何使函式为真值的物
件. 所以:

objects( (: clonep :) )

会传回游戏中所有的复制物件 (clones). 您也可以使用参数:

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_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)  函式:

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, ...) , 保留这种语法是为了与旧版相容.
任何普通函式合法 (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.
