背景:
阅读文章

LPC帮助文档—变量类型—函数

[日期:2007-05-10] 来源:  作者: [字体: ]

一篇偶翻译的文档,请指正。

             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" :) );
 

尊重作者 转载请注明出处52mud.com

收藏 推荐 打印 | 录入:sbso | 阅读:
相关内容      
内容推送
52mud提供
一起回忆泥巴游戏QQ群68186072
52mud官方微信公众平台
热门评论