Lua4.0 参考手册(四)4.6-4.8

(接上篇)
-------------------
4.6 可见性和 Upvalue
-------------------
一个函数体可以引用它自己的局部变量(包括它的参数)和全局变量,只要它们没有被函数中同名的局部变量所隐藏(shadowed )。一个不可以使用包含它的函数的局部变量,因为这样的变量可能在函数调用的时候已经不存在了。然而,一个函数可通过 upvalue 使用包含它的函数中的局部变量。upvalue 的语法如下:
    upvalue ::= `%‘ name
一个 upvalue 多少有点像是一个变量表达式,但是它的值是冻结的(frozen)当使用它的函数实例化时。upvalue 中使用的名字可以是任何变量的名字,只要函数定义的时候该变量是可见的,也就是说,直接包含它的函数中的全局变量和局部变量。注意,当 upvalue 是一个表时,只有表的引用(也就是 upvalue 的值)是冻结的。表的内容是可以任意修改的。使用表的值作为 upvalue 可以让函数有可写的但是私有的状态。
下面是一些例子:

    a,b,c = 1,2,3 -- global variables
    local d
    function f (x)
      local b = {} -- x and b are local to f; b shadows the global b
      local g = function (a)
        local y -- a and y are local to g
        p = a -- OK, access local `a‘
        p = c -- OK, access global `c‘
        p = b -- ERROR: cannot access a variable in outer scope
        p = %b -- OK, access frozen value of `b‘ (local to `f‘)
        %b = 3 -- ERROR: cannot change an upvalue
        %b.x = 3 -- OK, change the table contents
        p = %c -- OK, access frozen value of global `c‘
        p = %y -- ERROR: `y‘ is not visible where `g‘ is defined
        p = %d -- ERROR: `d‘ is not visible where `g‘ is defined
      end -- g
    end -- f

-------------------
4.7 错误处理
-------------------
由于 Lua 是一个扩展语言,所有的 Lua 动作从宿主程序中的 C 代码调用 Lua 库中的一个函数开始。每当一个错误在 Lua 编译或执行时发生,函数 _ERRORMESSAGE 将被调用(如果它不是 nil 的话),然后相应的库中的函数 (lua_dofile, lua_dostring, lua_dobuffer  和 lua_call) 被终止,并返回一个错误状态。

内存分配错误是上面规则的一个例外。当内存分配失败,Lua 也许不能执行 _ERRORMESSAGE 函数。因此,对于这种错误,Lua 不调用 _ERRORMESSAGE 函数,而是,库中相应的函数立即带一个特别的错误码(ERRMEM)返回。这个和其它的错误码定义在 lua.h 中,参见 5.8 节。

_ERRORMESSAGE 唯一的参数是一个描述错误的字符串。这个函数的默认定义叫做 _ALERT,它打印信息到 stderr (参见 6.1 节)。标准 I/O 库重定义了 _ERRORMESSAGE 并且使用调试机制(参见 7 节)去打印一些额外的信息,比如调用堆栈回溯。

Lua 代码可能通过显式调用函数 error (参见 6.1 节)生成一个错误。Lua 代码可以使用函数 call (参见 6.1 节)捕获一个错误。

-------------------
4.8 标签方法
-------------------
Lua 提供一个强大的机制去扩展它的语义,叫做标签方法 (tag method)。一个标签方法是一个程序员定义的在 Lua 程序执行的特定关键点调用的函数,它允许程序员在这些关键点上改变标准的 Lua 行为。每一个这样的点叫做一个事件。

特定事件的标签方法根据事件中的所涉及值的标签被调用(参见 3 节)。函数 settagmethod 改变给定对(tag,event)关联的标签方法。它的第一个参数是标签,第二个参数是事件的名字(一个字符串,参见下面),第三个参数是新的方法(一个函数),或者 nil 用来恢复对(标签事件对)的默认行为。settagmethod 函数返回标签事件对之前的标签方法。一个于之对应的函数 gettagmethod 接收一个标签和一个事件名并返回于之关联的当前方法。

标签方法在下面的事件中被调用,由给定名字区分。标签方法的语义可以由 Lua 函数描述解释器在每个事件的行为来更好的解释。这个函数不仅展示什么时候会调用标签方法,也展示它的参数,返回值和默认的行为。这里展示的代码仅用于说明目的;解释器中真正的行为是硬编码的,并且它比这个模拟更加的高效。这些解释(rawget, tonumber, call, etc.)中使用的所有的函数在 6.1 节中描述。

``add‘‘:
当 + 运算被应用于非数值型的操作数时会调用到它。
下面的函数 getbinmethod 定义了 Lua 如何为一个二元运算选择一个标签方法。首先,Lua 尝试第一个操作数,如果它的标签没有为操作定义标签方法;那么 Lua 将尝试第二个操作数,如果它依然失败,那么将从标签 0 获得一个标签方法。

    function getbinmethod (op1, op2, event)
      return gettagmethod(tag(op1), event) or
             gettagmethod(tag(op2), event) or
             gettagmethod(0, event)
    end

使用这个函数, ``add‘‘ 事件的标签方法是:

    function add_event (op1, op2)
      local o1, o2 = tonumber(op1), tonumber(op2)
      if o1 and o2 then -- both operands are numeric
        return o1+o2 -- ‘+‘ here is the primitive ‘add‘
      else -- at least one of the operands is not numeric
        local tm = getbinmethod(op1, op2, "add")
        if tm then
          -- call the method with both operands and an extra
          -- argument with the event name
          return tm(op1, op2, "add")
        else -- no tag method available: default behavior
          error("unexpected type at arithmetic operation")
        end
      end
    end

``sub‘‘:
当 - 运算被应用于非数值型的操作数时会调用到它。 它的行为类似于 ``add‘‘ 事件。

``mul‘‘:
当 * 运算被应用于非数值型的操作数时会调用到它。 它的行为类似于 ``add‘‘ 事件。

``div‘‘:
当 / 运算被应用于非数值型的操作数时会调用到它。 它的行为类似于 ``add‘‘ 事件。

``pow‘‘:
当 ^ (幂)运算调用时,即使对于数值型操作数。

    function pow_event (op1, op2)
      local tm = getbinmethod(op1, op2, "pow")
      if tm then
        -- call the method with both operands and an extra
        -- argument with the event name
        return tm(op1, op2, "pow")
      else -- no tag method available: default behavior
        error("unexpected type at arithmetic operation")
      end
    end

``unm‘‘:
当一元运算 - 被应用于非数值型的操作数时会调用到它。

    function unm_event (op)
      local o = tonumber(op)
      if o then -- operand is numeric
        return -o -- ‘-‘ here is the primitive ‘unm‘
      else -- the operand is not numeric.
        -- Try to get a tag method from the operand;
        -- if it does not have one, try a "global" one (tag 0)
        local tm = gettagmethod(tag(op), "unm") or
                   gettagmethod(0, "unm")
        if tm then
          -- call the method with the operand, nil, and an extra
          -- argument with the event name
          return tm(op, nil, "unm")
        else -- no tag method available: default behavior
          error("unexpected type at arithmetic operation")
        end
      end
    end

``lt‘‘:
当比较运算被应用于非数值型或非字符串型的操作数时会调用到它。它相当于 < 操作符。

    function lt_event (op1, op2)
      if type(op1) == "number" and type(op2) == "number" then
        return op1 < op2 -- numeric comparison
      elseif type(op1) == "string" and type(op2) == "string" then
        return op1 < op2 -- lexicographic comparison
      else
        local tm = getbinmethod(op1, op2, "lt")
        if tm then
          return tm(op1, op2, "lt")
        else
          error("unexpected type at comparison");
        end
      end
    end

其它的比较运算符使用这个标签方法根据常见的等值性:
    a>b <=> b<a
    a<=b <=> not (b<a)
    a>=b <=> not (a<b)

``concat‘‘:
当连结运算被应用于非字符串型的操作数时会调用到它。

    function concat_event (op1, op2)
      if (type(op1) == "string" or type(op1) == "number") and
         (type(op2) == "string" or type(op2) == "number") then
        return op1..op2 -- primitive string concatenation
      else
        local tm = getbinmethod(op1, op2, "concat")
        if tm then
          return tm(op1, op2, "concat")
        else
          error("unexpected type for concatenation")
        end
      end
    end

``index‘‘:
当 Lua 试图返回一个索引不在表中的值时会调用到它。语义参见 ``gettable‘‘ 事件。

``getglobal‘‘:
当 Lua 需要一个全局变量的值时会调用到它。这个方法可以只为 nil 设置,且只为由 newtag 新建的标签设置。注意标签是全局变量的当前值。

    function getglobal (varname)
      -- access the table of globals
      local value = rawget(globals(), varname)
      local tm = gettagmethod(tag(value), "getglobal")
      if not tm then
        return value
      else
        return tm(varname, value)
      end
    end

函数 getglobal 在基本库中被定义(参见 6.1 节)。

``setglobal‘‘:
当 Lua 给一个全局变量赋值时会调用到它。对于数值,字符串,表和有默认标签的 userdata 不可以设置这个方法。

    function setglobal (varname, newvalue)
      local oldvalue = rawget(globals(), varname)
      local tm = gettagmethod(tag(oldvalue), "setglobal")
      if not tm then
        rawset(globals(), varname, newvalue)
      else
        tm(varname, oldvalue, newvalue)
      end
    end

函数 setglobal 在基本库中被定义(参见 6.1 节)。

``gettable‘‘:
当 Lua 调用一个索引变量时会调用到它。对于有默认标签的表不可以设置这个方法。

    function gettable_event (table, index)
      local tm = gettagmethod(tag(table), "gettable")
      if tm then
        return tm(table, index)
      elseif type(table) ~= "table" then
        error("indexed expression not a table");
      else
        local v = rawget(table, index)
        tm = gettagmethod(tag(table), "index")
        if v == nil and tm then
          return tm(table, index)
        else
          return v
        end
      end
    end

``settable‘‘:
当 Lua 设置一个索引变量时会调用到它。对于有默认标签的表不可以设置这个方法。

    function settable_event (table, index, value)
      local tm = gettagmethod(tag(table), "settable")
      if tm then
        tm(table, index, value)
      elseif type(table) ~= "table" then
        error("indexed expression not a table")
      else
        rawset(table, index, value)
      end
    end

``function‘‘:
当 Lua 试图调用一个不是函数的值时会调用到它。

    function function_event (func, ...)
      if type(func) == "function" then
        return call(func, arg)
      else
        local tm = gettagmethod(tag(func), "function")
        if tm then
          for i=arg.n,1,-1 do
            arg[i+1] = arg[i]
          end
          arg.n = arg.n+1
          arg[1] = func
          return call(tm, arg)
        else
          error("call expression not a function")
        end
      end
    end

``gc‘‘:
当 Lua 垃圾回收一个 userdata 时会调用到它。这个标签方法只可以在 C 中设置,并且不可以设置给有默认标签的 userdata。对于每个被垃圾回收的 userdata, Lua 作和下面函数等价的操作:

    function gc_event (obj)
      local tm = gettagmethod(tag(obj), "gc")
      if tm then
        tm(obj)
      end
    end

在一个垃圾回收周期中,userdata 的标签方法被以标签创建的逆序调用,也就是说,被调用的第一个标签方法是关联于程序中创建的最后一个标签。而且,在周期结束时,Lua 做等价于 gc_event(nil) 调用的事情。
(未完待续)

时间: 2024-11-05 21:50:19

Lua4.0 参考手册(四)4.6-4.8的相关文章

Lua4.0 参考手册(一)1-3

说明:这个文档是 doc 目录里的 manual.html 文件.原文版权归原作者所有,这篇翻译只是作为学习之用.如果翻译有不当之处,请参考原文.-------------------以下是正文-------------------编程语言 Lua4.0 的参考手册--------------------------------------1 简介--------------------------------------Lua 是一个扩展编程语言,支持通用编程功能与数据描述功能.作为一个强大

Lua4.0 参考手册(八)6.2-6.5

(接上篇)-------------------6.2 字符串处理-------------------这个库提供字符串处理的通用函数,如查找,提取子串和模式匹配.在 Lua 中索引一个字符串的时候,第一个字符的索引是 1(不像 C 中是 0).另外,索引可以为负数,负数被解释为逆向索引,从字符串的结尾开始.所以,最后一个字符位置是 -1,以此类推. strbyte (s [, i])返回 s 的第 i 个字符的内部数值码(例如:ASCII 码).如果没有 i,它被认为是 1 .i 可以为负.

Lua4.0 参考手册(六)5.8-5.14

(接上篇)-------------------5.8 执行 Lua 代码-------------------一个宿主程序可以执行写在文件中或在字符串中的 Lua 块,使用下面的函数:     int lua_dofile (lua_State *L, const char *filename);     int lua_dostring (lua_State *L, const char *string);     int lua_dobuffer (lua_State *L, const 

Lua4.0 参考手册(二)4.1-4.4

(接上篇)--------------------------------------4 语言--------------------------------------这节描述 Lua 的词法,语法和语义. -------------------4.1 词法约定-------------------Lua 中的标识符可以是任何字母,数字,下划线组成的字符串,且首字母不可为数字.这符合大多数语言中标识符的定义,除了字母的字义依赖于当前的区域设置:所有的在当前的区域设置中被认为是字母的字符可以被用

Lua4.0 参考手册(七)6.1

(接上篇)--------------------------------------6 标准库--------------------------------------标准库提供了一些有用的函数,这些函数直接由标准 API 实现.因此,它们并非语言必需的部分,并且作为单独的 C 模块被提供.目前,Lua 有以下标准库:> 基本库:> 字符串处理:> 数学函数(sin, log, 等)> 输入输出(和一些系统功能) 为了能使用这些库,宿主程序必须调用函数 lua_baselibo

Lua4.0 参考手册(五)5.1-5.7

(接上篇)--------------------------------------5 API--------------------------------------这节描述 Lua 的 API, 也就是宿主程序和 Lua 交互的一组 C 函数.所有的 API 函数和相关联的类型及常量都在文件 lua.h 中声明. 所有的 API 提供的功能都可以由宏来替代,即使当我们使用术语函数(``function'').因为这样的宏只使用它的参数一次,所以不会产生隐蔽的副作用. ----------

Lua4.0 参考手册(三)4.5

(接上篇)-------------------4.5 表达式----------------------------4.5.1 基本表达式---------Lua 中基本表达式是:    exp ::= `(' exp `)'    exp ::= nil    exp ::= number    exp ::= literal    exp ::= var    exp ::= upvalue    exp ::= function    exp ::= functioncall    ex

Lua4.0 参考手册(九)7-8

(接上篇)--------------------------------------7 调试接口--------------------------------------Lua 没有内置的调试功能.而是借助于函数和钩子(hook)提供了一个特殊接口,可以用来构建不同种类的调试器,分析器(profile)和一些其它的需要解释器内部信息的工具.这个接口在 luadebug.h 文件中声明. -------------------7.1 栈和函数信息-------------------获得解释器

Vue.js 2.0 参考手册.CHM下载

下载地址 Vue.js 2.0 参考手册.CHM下载链接: http://pan.baidu.com/s/1kVbhd4b 密码: wxfh