您的位置:首页 > 房产 > 建筑 > 新手建站网址_贵州十大广告公司_搜狗收录批量查询_美国疫情最新情况

新手建站网址_贵州十大广告公司_搜狗收录批量查询_美国疫情最新情况

2025/3/10 12:03:22 来源:https://blog.csdn.net/woay2008/article/details/145672820  浏览:    关键词:新手建站网址_贵州十大广告公司_搜狗收录批量查询_美国疫情最新情况
新手建站网址_贵州十大广告公司_搜狗收录批量查询_美国疫情最新情况

文章目录

    • 2.7 – Error Handling
    • 2.8 – Metatables
    • 2.9 – Environments

2.7 – Error Handling

Because Lua is an embedded extension language, all Lua actions start from C code in the host program calling a function from the Lua library (see lua_pcall). Whenever an error occurs during Lua compilation or execution, control returns to C, which can take appropriate measures (such as printing an error message).

Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, you can use the pcall function.

例子:使用 lua_call 调用 Lua 函数

#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>int main() {lua_State *L = luaL_newstate();  // 创建一个新的 Lua 状态机luaL_openlibs(L);  // 打开 Lua 标准库// Lua 脚本代码,定义一个简单的函数,产生错误const char *script = "function foo() \n""   error('test error')\n""end\n";// 加载并执行 Lua 脚本if (luaL_dostring(L, script) != LUA_OK) {printf("Error loading script: %s\n", lua_tostring(L, -1));lua_close(L);return 1;}// 调用 Lua 函数,并处理错误lua_getglobal(L, "foo");// 使用 lua_call,如果出现错误,会直接终止进程lua_call(L, 0, 0);lua_close(L);  // 关闭 Lua 状态机return 0;
}

输出

PANIC: unprotected error in call to Lua API ([string "function foo() ..."]:2: test error)

出现错误会直接终止进程

例子:使用 lua_pcall 调用 Lua 函数

#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>int main() {lua_State *L = luaL_newstate();  // 创建一个新的 Lua 状态机luaL_openlibs(L);  // 打开 Lua 标准库// Lua 脚本代码,定义一个简单的函数,产生错误const char *script = "function foo() \n""   error('test error')\n""end\n";// 加载并执行 Lua 脚本if (luaL_dostring(L, script) != LUA_OK) {printf("Error loading script: %s\n", lua_tostring(L, -1));lua_close(L);return 1;}// 调用 Lua 函数,并处理错误lua_getglobal(L, "foo");int ret = lua_pcall(L, 0, 0, 0);if (ret != LUA_OK) {// 如果发生错误,打印错误信息printf("Error occurred: %s\n", lua_tostring(L, -1));}lua_close(L);  // 关闭 Lua 状态机return 0;
}

输出

Error occurred: [string "function foo() ..."]:2: test error

例子:使用 lua_pcall,自定义错误处理函数

#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>// 错误处理函数
int my_error_handler(lua_State *L) {const char *msg = lua_tostring(L, -1);  // 获取错误信息printf("Error in Lua code: %s\n", msg);  // 输出错误信息lua_pushliteral(L, "Error handled in my_error_handler");return 1;  // 返回 1,返回新的错误消息
}int main() {lua_State *L = luaL_newstate();  // 创建一个新的 Lua 状态机luaL_openlibs(L);  // 打开 Lua 标准库// 将错误处理函数压入栈中lua_pushcfunction(L, my_error_handler);// 定义 Lua 脚本,故意写一个错误的脚本(调用了未定义的函数 'foo')const char *script = "foo()  -- 这是一个错误,foo 未定义\n";if (luaL_loadstring(L, script) != 0) {printf("load error!\n");return 1;}// 使用 lua_pcall 执行 Lua 代码,并指定错误处理函数int ret = lua_pcall(L, 0, 0, -2);  // 执行 Lua 代码if (ret != LUA_OK) {// 如果发生错误,错误处理函数会将错误信息入栈printf("error msg: %s\n", lua_tostring(L, -1));}lua_close(L);  // 关闭 Lua 状态机return 0;
}

输出

Error in Lua code: [string "foo()  -- 这是一个错误,foo 未定义..."]:1: attempt to call global 'foo' (a nil value)
error msg: Error handled in my_error_handler

注意:error() 函数可以返回任意的值,并不是只能返回字符串。

2.8 – Metatables

Every value in Lua can have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable.

For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" in its metatable. If it finds one, Lua calls this function to perform the addition.

We call the keys in a metatable events and the values metamethods. In the previous example, the event is "add" and the metamethod is the function that performs the addition.

You can query the metatable of any value through the getmetatable function.

You can replace the metatable of tables through the setmetatable function. You cannot change the metatable of other types from Lua (except by using the debug library); you must use the C API for that.

Tables and full userdata have individual metatables (although multiple tables and userdata can share their metatables). Values of all other types share one single metatable per type; that is, there is one single metatable for all numbers, one for all strings, etc.

A metatable controls how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. A metatable also can define a function to be called when a userdata is garbage collected. For each of these operations Lua associates a specific key called an event. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) controls how Lua will perform the operation.

Metatables control the operations listed next. Each operation is identified by its corresponding name. The key for each operation is a string with its name prefixed by two underscores, ‘__’; for instance, the key for operation “add” is the string "__add". The semantics of these operations is better explained by a Lua function describing how the interpreter executes the operation.

The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. All functions used in these descriptions (rawget, tonumber, etc.) are described in §5.1. In particular, to retrieve the metamethod of a given object, we use the expression

     metatable(obj)[event]

This should be read as

     rawget(getmetatable(obj) or {}, event)

That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail (it simply results in nil).

  • “add”: the + operation.

    The function getbinhandler below defines how Lua chooses a handler for a binary operation. First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand.

         function getbinhandler (op1, op2, event)return metatable(op1)[event] or metatable(op2)[event]end
    

    By using this function, the behavior of the op1 + op2 is

         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 numericlocal h = getbinhandler(op1, op2, "__add")if h then-- call the handler with both operandsreturn (h(op1, op2))else  -- no handler available: default behaviorerror(···)endendend
    
  • “sub”: the - operation. Behavior similar to the “add” operation.

  • “mul”: the * operation. Behavior similar to the “add” operation.

  • “div”: the / operation. Behavior similar to the “add” operation.

  • “mod”: the % operation. Behavior similar to the “add” operation, with the operation o1 - floor(o1/o2)*o2 as the primitive operation.

  • “pow”: the ^ (exponentiation) operation. Behavior similar to the “add” operation, with the function pow (from the C math library) as the primitive operation.

  • “unm”: the unary - operation.

         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 handler from the operandlocal h = metatable(op).__unmif h then-- call the handler with the operandreturn (h(op))else  -- no handler available: default behaviorerror(···)endendend
    
  • “concat”: the … (concatenation) operation.

         function concat_event (op1, op2)if (type(op1) == "string" or type(op1) == "number") and(type(op2) == "string" or type(op2) == "number") thenreturn op1 .. op2  -- primitive string concatenationelselocal h = getbinhandler(op1, op2, "__concat")if h thenreturn (h(op1, op2))elseerror(···)endendend
    
  • “len”: the # operation.

         function len_event (op)if type(op) == "string" thenreturn strlen(op)         -- primitive string lengthelseif type(op) == "table" thenreturn #op                -- primitive table lengthelselocal h = metatable(op).__lenif h then-- call the handler with the operandreturn (h(op))else  -- no handler available: default behaviorerror(···)endendend
    

    See §2.5.5 for a description of the length of a table.

  • “eq”: the == operation. The function

    getcomphandler
    

    defines how Lua chooses a metamethod for comparison operators. A metamethod only is selected when both objects being compared have the same type and the same metamethod for the selected operation.

         function getcomphandler (op1, op2, event)if type(op1) ~= type(op2) then return nil endlocal mm1 = metatable(op1)[event]local mm2 = metatable(op2)[event]if mm1 == mm2 then return mm1 else return nil endend
    

    The “eq” event is defined as follows:

         function eq_event (op1, op2)if type(op1) ~= type(op2) then  -- different types?return false   -- different objectsendif op1 == op2 then   -- primitive equal?return true   -- objects are equalend-- try metamethodlocal h = getcomphandler(op1, op2, "__eq")if h thenreturn (h(op1, op2))elsereturn falseendend
    

    a ~= b is equivalent to not (a == b).

  • “lt”: the < operation.

         function lt_event (op1, op2)if type(op1) == "number" and type(op2) == "number" thenreturn op1 < op2   -- numeric comparisonelseif type(op1) == "string" and type(op2) == "string" thenreturn op1 < op2   -- lexicographic comparisonelselocal h = getcomphandler(op1, op2, "__lt")if h thenreturn (h(op1, op2))elseerror(···)endendend
    

    a > b is equivalent to b < a.

  • “le”: the <= operation.

         function le_event (op1, op2)if type(op1) == "number" and type(op2) == "number" thenreturn op1 <= op2   -- numeric comparisonelseif type(op1) == "string" and type(op2) == "string" thenreturn op1 <= op2   -- lexicographic comparisonelselocal h = getcomphandler(op1, op2, "__le")if h thenreturn (h(op1, op2))elseh = getcomphandler(op1, op2, "__lt")if h thenreturn not h(op2, op1)elseerror(···)endendendend
    

    a >= b is equivalent to b <= a. Note that, in the absence of a “le” metamethod, Lua tries the “lt”, assuming that a <= b is equivalent to not (b < a).

补充:


As we will see later, in Chapter 20, the string library sets a metatable for strings. All other types by default have no metatable:

print(getmetatable("hi")) --> table: 0x80772e0
print(getmetatable(10)) --> nil  

例子:元表的使用

Set = {}local mt = {} -- metatable for sets-- create a new set with the values of the given list
function Set.new (l)local set = {}setmetatable(set, mt)for _, v in ipairs(l) doset[v] = trueendreturn set
endfunction Set.union (a, b)if getmetatable(a) ~= mt or getmetatable(b) ~= mt thenerror("attempt to ’add’ a set with a non-set value", 2)endlocal res = Set.new{}for k in pairs(a) dores[k] = trueendfor k in pairs(b) dores[k] = trueendreturn res
endfunction Set.intersection (a, b)local res = Set.new{}for k in pairs(a) dores[k] = b[k]endreturn res
endfunction Set.tostring (set)local l = {} -- list to put all elements from the setfor e in pairs(set) dol[#l + 1] = eendreturn "{" .. table.concat(l, ", ") .. "}"
endmt.__tostring = Set.tostringmt.__add = Set.union
mt.__mul = Set.intersection--[[Metatables also allow us to give meaning to the relational operators, throughthe metamethods __eq (equal to), __lt (less than), and __le (less than or equalto). There are no separate metamethods for the other three relational operators,as Lua translates a~=b to not(a==b), a>b to b<a, and a>=b to b<=a.Until Lua 4.0, all order operators were translated to a single one, by translatinga<=b to not(b<a). However, this translation is incorrect when we have a partial order, that is, when not all elements in our type are properly ordered.For instance, floating-point numbers are not totally ordered in most machines,because of the value Not a Number (NaN). According to the IEEE 754 standard,currently adopted by virtually all floating-point hardware, NaN represents undefined values, such as the result of 0=0. The standard specifies that any comparison that involves NaN should result in false. This means that NaN<=x isalways false, but x<NaN is also false. It also implies that the translation froma<=b to not(b<a) is not valid in this case.In our example with sets, we have a similar problem. An obvious (anduseful) meaning for <= in sets is set containment: a<=b means that a is a subsetof b. With this meaning, again it is possible that both a<=b and b<a are false;therefore, we need separate implementations for __le (less or equal) and __lt(less than):
--]]mt.__le = function (a, b) -- set containmentfor k in pairs(a) doif not b[k] then return false endendreturn true
endmt.__lt = function (a, b)return a <= b and not (b <= a)
endmt.__eq = function (a, b)return a <= b and b <= a
ends1 = Set.new{10, 20, 30, 50}
s2 = Set.new{30, 1}
print(getmetatable(s1)) --> table: 00672B60
print(getmetatable(s2)) --> table: 00672B60s3 = s1 + s2
--[[
(Function print always calls tostring to format its output.) However, when
formatting any value, tostring first checks whether the value has a __tostring
metamethod. In this case, tostring calls the metamethod to do its job, passing
the object as an argument. Whatever this metamethod returns is the result of
tostring.
--]]
print(s3) --> {1, 10, 20, 30, 50}s1 = Set.new{2, 4}
s2 = Set.new{4, 10, 2}
print(s1 <= s2) --> true
print(s1 < s2) --> true
print(s1 >= s1) --> true
print(s1 > s1) --> false
print(s1 == s2 * s1) --> true

Functions setmetatable and getmetatable also use a metafield, in this case to protect metatables. Suppose you want to protect your sets, so that users can neither see nor change their metatables. If you set a __metatable field in the metatable, getmetatable will return the value of this field, whereas setmetatable will raise an error:

mt.__metatable = "not your business"
s1 = Set.new{}
print(getmetatable(s1)) --> not your business
setmetatable(s1, {})
stdin:1: cannot change protected metatable

  • “index”: The indexing access table[key].

         function gettable_event (table, key)local hif type(table) == "table" thenlocal v = rawget(table, key)if v ~= nil then return v endh = metatable(table).__indexif h == nil then return nil endelseh = metatable(table).__indexif h == nil thenerror(···)endendif type(h) == "function" thenreturn (h(table, key))     -- call the handlerelse return h[key]           -- or repeat operation on itendend
    

    补充:I said earlier that, when we access an absent field in a table, the result is nil. This is true, but it is not the whole truth. Actually, such accesses trigger the interpreter to look for an __index metamethod: if there is no such method, as usually happens, then the access results in nil; otherwise, the metamethod will provide the result.

    The archetypal example here is inheritance. Suppose we want to create several tables describing windows. Each table must describe several window parameters, such as position, size, color scheme, and the like. All these parameters have default values and so we want to build window objects giving only the non-default parameters. A first alternative is to provide a constructor that fills in the absent fields. A second alternative is to arrange for the new windows to inherit any absent field from a prototype window. First, we declare the prototype
    and a constructor function, which creates new windows sharing a metatable:

    Window = {} -- create a namespace
    -- create the prototype with default values
    Window.prototype = {x=0, y=0, width=100, height=100}
    Window.mt = {} -- create a metatable
    -- declare the constructor function
    function Window.new (o)setmetatable(o, Window.mt)return o
    endWindow.mt.__index =  Window.prototypew = Window.new{x=10, y=20}
    print(w.width) --> 100

  • “newindex”: The indexing assignment table[key] = value.

         function settable_event (table, key, value)local hif type(table) == "table" thenlocal v = rawget(table, key)if v ~= nil then rawset(table, key, value); return endh = metatable(table).__newindexif h == nil then rawset(table, key, value); return endelseh = metatable(table).__newindexif h == nil thenerror(···)endendif type(h) == "function" thenh(table, key,value)           -- call the handlerelse h[key] = value             -- or repeat operation on itendend
    

    补充:The default value of any field in a regular table is nil. It is easy to change this default value with metatables:

    local key = {} -- unique key
    local mt = {__index = function (t) return t[key] end}
    function setDefault (t, d)t[key] = dsetmetatable(t, mt)
    endtab = {x=10, y=20}
    print(tab.x, tab.z) --> 10 nil
    setDefault(tab, 0)
    print(tab.x, tab.z) --> 10 0

    Both __index and __newindex are relevant only when the index does not exist in the table. The only way to catch all accesses to a table is to keep it empty. So, if we want to monitor all accesses to a table, we should create a proxy for the real table. This proxy is an empty table, with proper __index and __newindex metamethods that track all accesses and redirect them to the original table.

    local index = {} -- create private indexlocal mt = { -- create metatable__index = function (t, k)print("*access to element " .. tostring(k))return t[index][k] -- access the original tableend,__newindex = function (t, k, v)print("*update of element " .. tostring(k) .." to " .. tostring(v))t[index][k] = v -- update original tableend
    }function track (t)local proxy = {}proxy[index] = tsetmetatable(proxy, mt)return proxy
    endt = {}
    t=track(t)
    t[2] = "hello" -- *update of element 2 to hello
    print(t[2]) -- *access to element 2
    

    It is easy to adapt the concept of proxies to implement read-only tables. All we have to do is to raise an error whenever we track any attempt to update the table. For the __index metamethod, we can use a table — the original table itself — instead of a function, as we do not need to track queries; it is simpler and rather more efficient to redirect all queries to the original table. This use, however, demands a new metatable for each read-only proxy, with __index pointing to the original table:

    function readOnly (t)local proxy = {}local mt = { -- create metatable__index = t,__newindex = function (t, k, v)error("attempt to update a read-only table", 2)end}setmetatable(proxy, mt)return proxy
    enddays = readOnly{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
    print(days[1]) --> Sunday
    days[2] = "Noday" --> attempt to update a read-only table
    

  • “call”: called when Lua calls a value.

         function function_event (func, ...)if type(func) == "function" thenreturn func(...)   -- primitive callelselocal h = metatable(func).__callif h thenreturn h(func, ...)elseerror(···)endendend
    

2.9 – Environments

Besides metatables, objects of types thread, function, and userdata have another table associated with them, called their environment. Like metatables, environments are regular tables and multiple objects can share the same environment.

Threads are created sharing the environment of the creating thread.

Userdata and C functions are created sharing the environment of the creating C function.

Non-nested Lua functions (created by loadfile, loadstring or load) are created sharing the environment of the creating thread. Nested Lua functions are created sharing the environment of the creating Lua function.

例子:

-- Non-nested function, created using loadstring (this is an example with loadstring)
local f1 = loadstring("return x + 10")  -- 假设 x 是全局变量
x = 10
print(f1())  -- 这里会使用全局变量 x,输出 20-- Nested function
function outer()local x = 5local function inner()return x + 10  -- 这里会访问到 outer 函数的局部变量 xendreturn inner()
endprint(outer())  -- 输出 15,内层函数访问的是外层函数的局部变量 x
-- 去掉 local x = 5,内层函数访问的是全局变量 x,则输出 20

Environments associated with userdata have no meaning for Lua. It is only a convenience feature for programmers to associate a table to a userdata.

Environments associated with threads are called global environments. They are used as the default environment for threads and non-nested Lua functions created by the thread and can be directly accessed by C code (see §3.3).

补充:在 C 代码中使用 lua_getglobal 可访问全局环境获取全局变量的值

void lua_getglobal (lua_State *L, const char *name);Pushes onto the stack the value of the global name. It is defined as a macro:#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)

The environment associated with a C function can be directly accessed by C code (see §3.3). It is used as the default environment for other C functions and userdata created by the function.

Environments associated with Lua functions are used to resolve all accesses to global variables within the function (see §2.3). They are used as the default environment for nested Lua functions created by the function.

You can change the environment of a Lua function or the running thread by calling setfenv. You can get the environment of a Lua function or the running thread by calling getfenv. To manipulate the environment of other objects (userdata, C functions, other threads) you must use the C API.

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com