Lua 学习笔记 (五)—— 基础库函数

基础库为 Lua 提供了一些核心函数。如果没有包含这个库,那么就可能需要自己来实现一些 Lua 语言特性了。

assert (v [, message])

如果其参数 v 的值为假(nilfalse), 它就调用 error; 否则,返回所有的参数。 在错误情况时, message 指那个错误对象; 如果不提供这个参数,参数默认为 “assertion failed!” 。

例子

assert(5==4,"Number Not Equal!")    --> 报错 Number Not Equal!
assert(nil)                         --> 报错 assertion failed!

collectgarbage (opt [, arg])

控制垃圾回收器的参数有两个,pause 和 step multipier。

参数 pause 控制了收集器在开始一个新的收集周期之前要等待多久。 随着数字的增大就导致收集器工作工作的不那么主动。 小于 1 的值意味着收集器在新的周期开始时不再等待。 当值为 2 的时候意味着在总使用内存数量达到原来的两倍时再开启新的周期。

参数 step multiplier 控制了收集器相对内存分配的速度。 更大的数字将导致收集器工作的更主动的同时,也使每步收集的尺寸增加。 小于 1 的值会使收集器工作的非常慢,可能导致收集器永远都结束不了当前周期。 缺省值为 2 ,这意味着收集器将以内存分配器的两倍速运行。

该函数是垃圾回收器的通用接口,根据 opt 参数的不同实现不同的功能。

  • “stop”: 停止垃圾回收。
  • “restart”: 重启垃圾回收。
  • “collect”: 执行垃圾回收的完整循环。
  • “count”: 返回 Lua 当前使用的总内存(单位为 Kb)。
  • “step”: 执行一步(一步可由多步组成)垃圾回收。步数可由参数 arg 控制(值越大,步数越多,0 表示执行一步(指最小的一步))。如果执行后完成了回收循环,返回 true
  • “setpause”: 把 arg/100 作为垃圾回收参数 pause 的新值。
  • “setstepmul”: 把 arg/100 作为垃圾回收参数 step mutiplier 的新值。

例子

进行垃圾回收前后的内存占用情况:

x = collectgarbage("count")
print(x)            --> 27.5615234375
collectgarbage("collect")
x = collectgarbage("count")
print(x)            --> 26.7490234375

dofile (filename)

打开该名字的文件,并执行文件中的 Lua 代码块。 不带参数调用时, dofile 执行标准输入的内容(stdin)。 返回该代码块的所有返回值。 对于有错误的情况,dofile 将错误反馈给调用者 (即,dofile 没有运行在保护模式下)。

例子

同一目录下新建两个 Lua 文件,代码及输出:

-- another.lua
return "Message from another file!"

-- sample.lua
x = dofile("./another.lua")
print(x)    --> Message from another file!

dofile 在这里等价于

function dofile()
    function func()
        return "Message from another file!"
    end

    return func()
end

于是等价的输出为

print(dofile()) --> Message from another file!

error (message [, level])

终止所保护的函数,抛出 message 消息,不再返回。

通常这个函数会在抛出的消息前面加上发生错误的地址信息。堆栈等级决定添加哪个地址。如果堆栈等级为 0 ,不返回地址信息;如果为 1,返回 error 语句所在位置;如果为 2,返回调用 error所在函数的位置;依此类推。

定义

error([报错消息],[堆栈等级]=1)

例子

function division(a,b)
    if b == 0 then error("Divisor cannot be 0!",2) end      -- level 值为 1 时,错误信息指向这里
    return a / b
end

print(division(5,1))
print(division(5,0))        -- level 值为 2 时,错误信息指向这里

_G

_G 持有全局环境的变量,Lua 本身用不到这个变量,更改变量不会影响到全局环境;反过来也一样。

getfenv (f)

返回函数的环境。 f 可以是一个 Lua 函数,也可以是函数在堆栈中的等级。等级 1 代表调用 getfenv() 的那个函数。如果传入的函数不是 Lua 函数,或者 f 是 0,那么 getfenv 返回 全局环境。

~~[待补充]不是太明白,没能给出合适的代码~~
参考 Lua中的环境概念

定义

getfenv([目标函数]=1)

例子

获取全局环境:

for k,v in pairs(_G) do
print(k,v)
end

--string            table: 0x7ff200f02330
--xpcall            function: 0x7ff200d03cc0
--package           table: 0x7ff200e00000
--tostring          function: 0x7ff200d04560
--print             function: 0x7ff200d046a0
--os                table: 0x7ff200f01cb0
--unpack            function: 0x7ff200d04610
--require           function: 0x7ff200f006f0
--getfenv           function: 0x7ff200d042f0
--setmetatable      function: 0x7ff200d044a0
--next              function: 0x7ff200d04260
--assert            function: 0x7ff200d03fc0
--tonumber          function: 0x7ff200d04500
--io                table: 0x7ff200f014a0
--rawequal          function: 0x7ff200d046f0
--collectgarbage    function: 0x7ff200d04010
--arg               table: 0x7ff200e01360
--getmetatable      function: 0x7ff200d04340
--module            function: 0x7ff200f006a0
--rawset            function: 0x7ff200d047a0
--math              table: 0x7ff200e00040
--debug             table: 0x7ff200e00a00
--pcall             function: 0x7ff200d042b0
--table             table: 0x7ff200f00790
--newproxy          function: 0x7ff200d04820
--type              function: 0x7ff200d045c0
--coroutine         table: 0x7ff200d048c0
--_G                table: 0x7ff200d02fc0
--select            function: 0x7ff200d04400
--gcinfo            function: 0x7ff200d03000
--pairs             function: 0x7ff200d03e00
--rawget            function: 0x7ff200d04750
--loadstring        function: 0x7ff200d04200
--ipairs            function: 0x7ff200d03d70
--_VERSION          Lua 5.1
--dofile            function: 0x7ff200d04110
--setfenv           function: 0x7ff200d04450
--load              function: 0x7ff200d041b0
--error             function: 0x7ff200d04160
--loadfile          function: 0x7ff200d043a0

getmetatable (object)

如果对象没有元表,返回空;如果对象有 __metatable 域,返回对应的值;否则,返回对象的元表。

例子

对象有 __metatable 域的情况:

t = {num = "a table"}

mt = {__index = {x = 1,y = 2},__metatable = {__index = {x = 5,y = 6}}}
setmetatable(t, mt)

print(getmetatable(t).__index.x)  --> 5
print(t.x)                        --> 1

~~进行操作时的元表依旧是与值直接关联的那个元表,不知道这样子处理有什么作用?~~

ipairs (t)

返回三个值:迭代器、传入的表 t、值 0 。迭代器能够根据传入的表 t 和索引 i 得到 i+1 和 t[i+1] 的值。

其实现形式类似于这样:

function ipairs(t)

    function iterator(t,i)
        i = i + 1
        i = t[i] and i      -- 如果 t[i] == nil 则 i = nil;否则 i = i
        return i,t[i]
    end

    return iterator,t,0

end

例子

使用 ipairs 对表进行遍历,会从键值为 1 开始依次向后遍历,直到值为 nil。

t = {"1","2",nil,[4]="4"}
-- t = {"1","2",[4]="4"}   -- 使用该表会得到相同的输出

for i,v in ipairs(t) do
    print(i,v)
end

--> 1   1
--> 2   2

load (func [, chunkname])

通过传入函数 func 的返回值获取代码块片段。func 函数的后一次调用返回的字符串应当能与前一次调用返回的字符串衔接在一起,最终得到完整的代码块。函数返回 nil 或无返回值时表示代码块结束。

load 函数会将得到的代码块作为函数返回。返回函数的环境为全局环境。如果出现错误,load 会返回 nil 和 错误信息。

chunkname 作为该代码块的名称,用在错误信息与调试信息中。

例子

[待补充]

loadfile ([filename])

使用方式与 dofile 类似,函数内容与 load 类似。从文件中获取代码块,如果没有指定文件,则从标准输入中获取。

loadfile 把文件代码编译为中间码,以文件代码作为一个代码块(chunk),并返回包含此代码块的函数。
编译代码成中间码,并返回编译后的chunk作为一个函数。 如果出现错误,则返回 nil 以及错误信息。

使用 loadfile,可以一次编译多次运行;而每次使用 dofile,都会执行一次编译。

例子

同一目录下新建两个 Lua 文件,代码及输出:

-- sample.lua
f = loadfile("./sample.lua")
print(f())
--> Message from another file!
--> 0

-- another.lua
function fun()
 print("Message from another file!")
 return 0
end
res = fun()
return res

loadfile 在这里等价于

function loadfile()
    function fun()
     print("Message from another file!")
     return 0
    end
    res = fun()
    return res
end

loadstring (string [, chunkname])

与 load 类似,只不过是从字符串中获取代码块。

要想加载并运行所给的字符串,使用如下惯用形式:

assert(loadingstring(s))()

next (table [, index])

返回传入的表中下一个键值对。

定义

next([表],[键]=nil)

第一个参数是要操作的表,第二个参数是表中的某个键。如果传入的键值为 nil ,则函数返回第一个键值对。如果传入一个有效的键值,则输出下一对键值对。如果没有下一个键值对,返回 nil。

根据定义,可以使用 next 来判断一个表是否为空表。

注意:

键值对的遍历顺序是不一定的,即使是对数字索引也是如此。如果想要按照数字索引的顺序获取键值对,参见 ipairs (t) 函数。

例子

t = {"table",["a"] = 5, ["c"] = 6}

-- index 为 nil
print(next(t, nil))         --> 1   table

-- index 为 无效键
print(next(t,"d"))          --> 编译错误

-- index 为 数字索引
print(next(t,1))            --> a   5

-- index 为 一般键
print(next(t, "a"))         --> c   6

-- index 为 最后一个键
print(next(t,"c"))          --> nil

遍历顺序与定义顺序不一致的例子:

t = {[1]="table",b = 4,["a"] = 5, ["c"] = 6, func}

t.func = function (...)
    return true
end

for k,v in pairs(t) do
    print(k,v)
end
--> a   5
--> func    function: 0x7f7f63c0ad50
--> c   6
--> b   4

而且从上面的例子中可以看出 name = exp 的键值对形式会占用

pairs (t)

返回三个值:next 函数,表 t,nil。通常用来遍历表中的所有键值对。
如果 t 有元方法 __pairs ,将 t 作为参数 传入该函数并返回前三个返回值。

在使用 pairs 函数遍历表的过程中,可以删除域或者修改已有的域,但是如果添加新的域,可能出现无法预期的问题。

例子

t = {"table",["a"] = 5, ["c"] = 6}
for k,v in pairs(t) do
    print(k,v)
end
--> 1   table
--> a   5
--> c   6

在遍历表的过程中添加新的域导致问题出现的情况:

t = {"table",["a"] = 5, ["c"] = 6}

for k,v in pairs(t) do
    -- 添加一个新的域
    if k == 'a' then
        t[2] = 8
    end
    print(k,v)
end
--> 1   table
--> a   5

pcall (f [, arg1, …])

以保护模式调用传入的函数,也就是说不会抛出错误。如果捕获到抛出的错误,第一个参数返回 false,第二个参数返回错误信息;如果没有出现错误,第一个参数返回 ture,后面的参数返回传入函数的返回值。

#

function fun(a,b)

    assert(not(b == 0), "divisor can't be 0 !")

    return a / b    
end

success, res = pcall(fun,5,0) --> false .../sample.lua:3: divisor can't be 0 !
success, res = pcall(fun,5,1) --> true  5

print (…)

仅作为快速查看某个值的工具,不用做格式化输出。正式的格式化输出见 string.format 与 io.write。

rawequal (v1, v2)

raw 作为前缀的函数均表示该方法在不触发任何元方法的情况下调用。

rawequal 检查 v1 是否与 v2 相等,返回比较结果。

例子

t = {"value"}
s = "value"
s2 = "value"
print(rawequal(t, s))     --> false
print(rawequal(s, s2))    --> true

rawget (table, index)

获取 table 中键 index 的关联值,table 参数必须是一个表,找不到返回 nil 。

例子

t = {"value",x = 5}

print(rawget(t, 1))     --> value
print(rawget(t, "x"))   --> 5
print(rawget(t, 2))     --> nil
print(rawget("value",1))--> bad argument #1 to 'rawget' (table expected, got string)

rawset (table, index, value)

将 table[index] 的值设置为 value 。table 必须是一张表,index 不能是 nil 或 NaN 。value 可以是任何值。返回修改后的 table 。

例子

t = {"value",x = 5}
t2 = {"sub table"}
rawset(t, 1,"new value")
rawset(t, "y", 6)
rawset(t, t2,"sub table")
rawset(t,NaN,"NaN")         --> table index is nil

print(t[1])                 --> new value
print(t.y)                  --> 6
print(t[t2])                --> sub table

select (index, …)

index 可以是数字或者字符 ‘#’ 。当 index 为数字时,返回第 index + 1 个参数及后面的参数(支持负数形式的 index);当 index 为 ‘#’ 时,返回参数的个数(不包括第一个参数)。

例子

t = {"table",x = 5}
t2 = {"table2"}

print(select(  1, 1, t, t2))    --> 1  table: 0x7fad7bc0a830 table: 0x7fad7bc0ac20
print(select( -3, 1, t, t2))    --> 1  table: 0x7fad7bc0a830 table: 0x7fad7bc0ac20
print(select("#", 1, t, t2))    --> 3

setfenv (f, table)

设置函数 f 的环境表为 table 。f 可以是一个函数,或者是代表栈层级的数字。栈层级为 1 的函数是那个调用 setfenv 的函数,栈层级为 2 的函数就是更上一层的函数。 setfenv 返回 f。

特别的,如果 f 为 0,那么 setfenv 会把全局环境设置为 table 。并且不做任何返回。

Lua 的之后版本中去掉了 setfenv 和 getfenv 函数。

例子

使用栈层级操作 setfenv 的例子:

function foobar(...)

    -- 设置 foobar 的环境
    t = {}
    setmetatable(t, {__index = _G })
    setfenv(1,t)
    a = 1
    b = 2

    -- 输出 foobar 的环境
    for k,v in pairs(getfenv(1)) do
        print(k,v)
    end
    print()

    function foo(...)
        -- 设置 foo 的环境,继承 foobar 的环境
        local t = {}
        setmetatable(t, {__index = _G})
        setfenv(1,t)
        x = 3
        y = 4

        -- 输出 foo 的环境
        for k,v in pairs(getfenv(1)) do
            print(k,v)
        end
        print()

        -- 再次设置 foobar 的环境
        setfenv(2, t)
    end


    foo()

    -- 再次输出 foobar 的环境
    for k,v in pairs(getfenv(1)) do
        print(k,v)
    end
end

foobar()

--> a   1
--> b   2
--> 
--> y   4
--> x   3
--> 
--> y   4
--> x   3

将 setfenv 用于模块加载:

-- sample.lua 文件
local FuncEnv={}    -- 作为环境
setmetatable(FuncEnv, {__index = _G}) -- 为了能够访问原本全局环境的值,将全局环境表(_G)放在元表中

local func=loadfile("other.lua")    -- 返回一个函数,函数以 other 文件内容作为代码块
setfenv(func,FuncEnv)
func()                              -- 执行代码块,得到定义的 message 函数,该函数会存在环境中
FuncEnv.message()                   --通过环境调用函数,FuncEnv 此时就相当于一个独立模块
-- other.lua 文件
function message()
    print("Message from another file!")
end

本小节参考了 斯芬克斯设置函数环境——setfenvicydaylua5.1中的setfenv使用 两篇博客。

setmetatable (table, metatable)

给 table 关联元表 metatable 。返回参数 table 。

如果元表定义了 __metatable 域,会抛出错误。

metatable 参数为 nil 表示解除已经关联的元表。

例子

-- 关联一个定义了加法操作的元表
t = setmetatable({}, {__add = function(a,b)
    if type(a) == "table" and type(b) == "table" then
        return a.num + b.num
    end
end})

t.num = 5
t2 = {num = 6}
print(t+t2)         --> 11      -- 只要有一个表进行了关联就能够进行运算

setmetatable(t, nil)            

-- 解除关联后再进行加法运算会报错
print(t+t2)         --> attempt to perform arithmetic on global 't' (a table value)

tonumber (e [, base])

tonumber([值],[基数]=10)

尝试把 e 转换为十进制数值并返回。如果无法转换返回 nil 。

base 表示传入参数的进制,默认为 10 进制。base 的可输入范围 [2,36]。高于 10 的数字用字母表示,A-Z 分别表示 11-35 。

例子

print(tonumber(123))            --> 123
print(tonumber("123"))          --> 123
print(tonumber("abc"))          --> nil
print(tonumber("abc", 20))      --> 4232
print(tonumber("ABC", 20))      --> 4232

tostring (e)

能将任意类型的值转换为合适的字符串形式返回。要控制数字转换为字符串的方式,使用 string.format(formatstring,…)

如果值所关联的元表有 __tostring 域,则使用该域的元方法获取字符串。

例子

function func()
    print("this is a function")
end
t = {name = "table"}

print(tostring(123))        --> 123
print(tostring("abc"))      --> abc
print(tostring(func))       --> function: 0x7f86348013b0
print(tostring(t))          --> table: 0x7f86348013e0

type (v)

返回 v 的类型,类型以字符串形式返回。 有以下八种返回值: “nil” , “number”, “string”, “boolean”, “table”, “function”, “thread”, “userdata”。

例子

type(nil)                   --> "nil"
type(false)                 --> "boolean"
type(123)                   --> "number"
type("abc")                 --> "string"

print(type(nil) == "nil")   --> true

unpack (list [, i [, j]])

unpack([列表],[起始位置]=1,[返回个数]=[列表长度])

返回表中的各个域的值,等价于返回

return list[i], list[i+1], ···, list[j]

例子

t = {1,2,3,a = 4,b = 5}

print(unpack(t, 1, 4))      --> 1   2   3   nil

_VERSION

包含有当前解释器版本号的全局变量,当前版本的值为 “Lua 5.1″。

xpcall (f, err [, arg1, …]

pcall (f, arg1, …) 类似。不同的是,如果 f 函数抛出了错误,那么 xpcall 不会返回从 f 抛出的错误信息,而是使用 err 函数返回的错误信息。

例子

function fun(a,b)   -- 这里的参数没什么实际作用,就是展示下用法
    error("something wrong !!", 1)
end

-- pcall 
local success, res = pcall(fun,1,2)
print(success,res)      --> false   .../sample.lua:2: something wrong !!

-- xpcall
local success, res = xpcall(fun,function()
    return "an error occured !!"
end,1,2)
print(success,res)      --> false   an error occured !!

参考链接

设置函数环境——setfenv(解释了如何方便地设置函数的环境,以及为什么要那样设置)
lua5.1中的setfenv使用(介绍了该环境的设置在实际中的一个应用)
Lua入门系列-果冻想(对Lua进行了较为全面的介绍)

    原文作者:tangyikejun
    原文地址: https://segmentfault.com/a/1190000002735930
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞