软件开发中的原表是啥呢?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件开发中的原表是啥呢?相关的知识,希望对你有一定的参考价值。
软件开发中的原表是什么呢?
参考技术A给指定表设置元表。 (你不能在 L ua 中改变其它类型值的元表,那些只能在 C 里做。) 如果 metatable 是 nil, 将指定表的元表移除。 如果原来那张元表有 "__metatable" 域,抛出一个错误。
这个函数返回 table。
如果调用的时候没有 base, tonumber 尝试把参数转换为一个数字。 如果参数已经是一个数字,或是一个可以转换为数字的字符串, tonumber 就返回这个数字; 否则返回 nil。
字符串的转换结果可能是整数也可能是浮点数, 这取决于 Lua 的转换文法。 (字符串可以有前置和后置的空格,可以带符号。)
当传入 base 调用它时, e 必须是一个以该进制表示的整数字符串。 进制可以是 2 到 36 (包含 2 和 36)之间的任何整数。 大于 10 进制时,字母 'A' (大小写均可)表示 10 , 'B' 表示 11,依次到 'Z' 表示 35 。 如果字符串 e 不是该进制下的合法数字, 函数返回 nil。
可以接收任何类型,它将其转换为人可阅读的字符串形式。 浮点数总被转换为浮点数的表现形式(小数点形式或是指数形式)。 (如果想完全控制数字如何被转换,可以使用 string.format。)
如果 v 有 "__tostring" 域的元表, tostring 会以 v 为参数调用它。 并用它的结果作为返回值。
开始或继续协程 co 的运行。 当你第一次延续一个协程,它会从主体函数处开始运行。 val1, ... 这些值会以参数形式传入主体函数。 如果该协程被让出,resume 会重新启动它; val1, ... 这些参数会作为让出点的返回值。
如果协程运行起来没有错误, resume 返回 true 加上传给 yield 的所有值 (当协程让出), 或是主体函数的所有返回值(当协程中止)。 如果有任何错误发生, resume 返回 false 加错误消息。
返回当前正在运行的协程加一个布尔量。 如果当前运行的协程是主线程,其为真。
以字符串形式返回协程 co 的状态: 当协程正在运行(它就是调用 status 的那个) ,返回 "running"; 如果协程调用 yield 挂起或是还没有开始运行,返回 "suspended"; 如果协程是活动的,都并不在运行(即它正在延续其它协程),返回 "normal"; 如果协程运行完主体函数或因错误停止,返回 "dead"。
创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回一个函数, 每次调用该函数都会延续该协程。 传给这个函数的参数都会作为 resume 的额外参数。 和 resume 返回相同的值, 只是没有第一个布尔量。 如果发生任何错误,抛出这个错误。
Lua中的元表与元方法
前言
__add(a, b) --加法
__sub(a, b) --减法
__mul(a, b) --乘法
__div(a, b) --除法
__mod(a, b) --取模
__pow(a, b) --乘幂
__unm(a) --相反数
__concat(a, b) --连接
__len(a) --长度
__eq(a, b) --相等
__lt(a, b) --小于
__le(a, b) --小于等于
__index(a, b) --索引查询
__newindex(a, b, c) --索引更新(PS:不懂的话,后面会有讲)
__call(a, ...) --执行方法调用
__tostring(a) --字符串输出
__metatable --保护元表
t = {}
print(getmetatable(t)) --> nil
t1 = {}
setmetatable(t, t1)
assert(getmetatable(t) == t1)
接下来就介绍介绍如果去重新定义这些方法。
算术类的元方法
Set = {}
local mt = {} -- 集合的元表
-- 根据参数列表中的值创建一个新的集合
function Set.new(l)
local set = {}
setmetatable(set, mt)
for _, v in pairs(l) do set[v] = true end
return set
end
-- 并集操作
function Set.union(a, b)
local retSet = Set.new{} -- 此处相当于Set.new({})
for v in pairs(a) do retSet[v] = true end
for v in pairs(b) do retSet[v] = true end
return retSet
end
-- 交集操作
function Set.intersection(a, b)
local retSet = Set.new{}
for v in pairs(a) do retSet[v] = b[v] end
return retSet
end
-- 打印集合的操作
function Set.toString(set)
local tb = {}
for e in pairs(set) do
tb[#tb + 1] = e
end
return "{" .. table.concat(tb, ", ") .. "}"
end
function Set.print(s)
print(Set.toString(s))
end
Set = {}
local mt = {} -- 集合的元表
-- 根据参数列表中的值创建一个新的集合
function Set.new(l)
local set = {}
setmetatable(set, mt)
for _, v in pairs(l) do set[v] = true end
return set
end
local set1 = Set.new({10, 20, 30})
local set2 = Set.new({1, 2})
print(getmetatable(set1))
print(getmetatable(set2))
assert(getmetatable(set1) == getmetatable(set2))
mt.__add = Set.union
local set1 = Set.new({10, 20, 30})
local set2 = Set.new({1, 2})
local set3 = set1 + set2
Set.print(set3)
-
对于二元操作符,如果第一个操作数有元表,并且元表中有所需要的字段定义,比如我们这里的__add元方法定义,那么Lua就以这个字段为元方法,而与第二个值无关; -
对于二元操作符,如果第一个操作数有元表,但是元表中没有所需要的字段定义,比如我们这里的__add元方法定义,那么Lua就去查找第二个操作数的元表; -
如果两个操作数都没有元表,或者都没有对应的元方法定义,Lua就引发一个错误。
比如set3 = set1 + 8这样的代码,就会打印出以下的错误提示:
lua: test.lua:16: bad argument #1 to 'pairs' (table expected, got number)
function Set.union(a, b)
if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
error("metatable error.")
end
local retSet = Set.new{} -- 此处相当于Set.new({})
for v in pairs(a) do retSet[v] = true end
for v in pairs(b) do retSet[v] = true end
return retSet
end
__tostring元方法
函数print总是调用tostring来进行格式化输出,当格式化任意值时,tostring会检查该值是否有一个tostring的元方法,如果有这个元方法,tostring就用该值作为参数来调用这个元方法,剩下实际的格式化操作就由__tostring元方法引用的函数去完成,该函数最终返回一个格式化完成的字符串。例如以下代码:
mt.__tostring = Set.toString
如何保护我们的“奶酪”——元表
function Set.new(l)
local set = {}
setmetatable(set, mt)
for _, v in pairs(l) do set[v] = true end
mt.__metatable = "You cannot get the metatable" -- 设置完我的元表以后,不让其他人再设置
return set
end
local tb = Set.new({1, 2})
print(tb)
print(getmetatable(tb))
setmetatable(tb, {})
{1, 2}
You cannot get the metatable
lua: test.lua:56: cannot change a protected metatable
__index元方法
-
当访问一个table的字段时,如果table有这个字段,则直接返回对应的值; -
当table没有这个字段,则会促使解释器去查找一个叫__index的元方法,接下来就就会调用对应的元方法,返回元方法返回的值; -
如果没有这个元方法,那么就返回nil结果。
Windows = {} -- 创建一个命名空间
-- 创建默认值表
Windows.default = {x = 0, y = 0, width = 100, height = 100, color = {r = 255, g = 255, b = 255}}
Windows.mt = {} -- 创建元表
-- 声明构造函数
function Windows.new(o)
setmetatable(o, Windows.mt)
return o
end
-- 定义__index元方法
Windows.mt.__index = function (table, key)
return Windows.default[key]
end
local win = Windows.new({x = 10, y = 10})
print(win.x) -- >10 访问自身已经拥有的值
print(win.width) -- >100 访问default表中的值
print(win.color.r) -- >255 访问default表中的值
-- 定义__index元方法
Windows.mt.__index = Windows.default
__newindex元方法
-
如果有了元表,就查找元表中是否有__newindex元方法;如果没有元表,就直接添加这个索引,然后对应的赋值; -
如果有这个__newindex元方法,Lua解释器就执行它,而不是执行赋值; -
如果这个__newindex对应的不是一个函数,而是一个table时,Lua解释器就在这个table中执行赋值,而不是对原来的table。
local tb1 = {}
local tb2 = {}
tb1.__newindex = tb2
tb2.__newindex = tb1
setmetatable(tb1, tb2)
setmetatable(tb2, tb1)
tb1.x = 10
loop in settable
以上是关于软件开发中的原表是啥呢?的主要内容,如果未能解决你的问题,请参考以下文章