Lua流水账0

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SHIYUEDYX/article/details/80436392

lua编译器下载地址:https://github.com/rjpcomputing/luaforwindows/releases
使用版本:LuaForWindows_v5.1.5-52
使用书籍:Lua-Chinese
1.在控制结构的条件中除了false和nil为假,其他都为真,也就是0和空串也为真。

2.常用转义序列:\n(换行),\t(制表符),\r(回车)

3.可用[[..]]表示字符串,这种表示的字符串支持多行,可嵌套且不解释转义语句,若第一行是换行符,则会自动忽略。若[[..]]中嵌套了一个[[..]],需要写成[=[..[[..]]..]=]的形式,其中=可任意多个,但是前后需要个数相同。
例:

page = [==[
    <"this is a test"\>
    [[<"this is a body test"\>]]
]==]
print(page);

4.当用..连接两个数字时,为了避免解释出错,需要在数字后加空格

print(10 .. 20)

5.若tonumber中的参数不是一个string返回值为nil

6.==比较tables,userdata,functions时,比较他们的引用,引用不一致,就算内容一样也是false

7.a and b:若a为false返回a,否则返回b。a or b:若a为true返回a,否则返回b。not的结果一直返回true或者false.
此规则可用于当x为false或nil时赋初值:x = x or v

8.三元运算符的实现:a ? b : c ⇒ (a and b) or c

9.表可以直接赋值初始化,也可以使用任何表达式初始化。当初始化一个表作为record使用:a = {x = 0, y = 0} => a.x = 0; a.y = 0; =>a[“x”] = 0,a[“y”]=0 =>{[“x”] = 0,[“y”] = 0},其中分隔符可以用,也可以用;,通常我们使用;来分割不同类型的表元素。
例:链表实现

local list = nil;
for k,line in pairs({"begin","yes","no","end"}) do
    list = {next = list, value = line}
end
while list do
    print("this is list value "..list.value);
    list = list.next;
end

10.lua可以对多个变量同时赋值,变量列表和值列表的各个元素用,隔开。赋值语句右边的值会依次赋给左边的值。而且lua会先计算好右边所有的值,然后才进行赋值操作。根据这一特性,可以这样实现变量交换
例:

a = 1;b = 2;
a,b = b,a;
print("this a and b " .. a ..":"..b)

11.赋值时,若变量个数与值个数不一致,如果变量个数多余值个数,则多余的变量赋nil,若变量个数小于值个数,则多余的值会被忽略。

12.一个关于作用域的例子:

x = 10
local i = 1
while i <= x do                        --外部x
    local x = i * 2;                   --内部x
    print(x);
    i = i + 1;
end
if i > 20 then
    local x;
    x = 20;
    print(x + 2);
else
    print(x);
end
print(x);

13.使用局部变量(local)的两个好处:避免命名冲突,局部变量的访问速度比全局变量要快。

14.do..end句型可以给block划定一个更明确的界限,在这个里面的局部变量的作用域被包含在do..end之间。
15.控制语句句式:if…then…end,if…then…else…end,if…then…elseif…then…else….end

16.while语句:while…do…end

17.repeat-until语句:repeat…until…

18.for语句:for beginvalue,endvalue,stepvalue do…end =>其中beginvalue,endvalue,stepvalue都是局部变量
for k,v in ipairs(a) do … end,for k,v in pairs(a) do … end =>其中k,v是局部变量

19.lua语法要求break和return只能出现在block的结尾一句,也就是在end或else或until之前,也可以使用do break/return end来实现这一目的。

20.函数调用时,若函数参数是字符串或者表构造的时候,可以不写()
例:

function f(table)
    print "this is a table func";
end
print "Hello World";
f{"table"}

21.函数形参和实参的匹配和赋值语句类似,多余部分忽略,缺少部分nil补足。

22.对于多返回值函数可用()强制返回一个值。
例:

function f2()
    return "a","b";
end
--输出:a b
print(f2());
--输出:a
print((f2()));
--输出:a c
print(f2(),"c");
--输出:ad
print(f2().."d");
local tableA = {"1",f2()};
for k, v in pairs(tableA) do
    --输出:1:1,2:a,3:b
    print("this is tableA key and value : "..k..":"..v);
end
local tableB = {"1",f2(),"3"};
for k,v in pairs(tableB) do
    --输出:1:1,2:a,3:3
    print("this is tableB key and value : "..k..":"..v);
end
temp1,temp2,temp3 = f2();
--输出:a b nil
print(temp1,temp2,temp3);
b1,b2,b3 = f2(),10,30;
--输出:a,10,30
print(b1,b2,b3);
function f0()
end
a1,a2 = f0(),10,30;
--输出:nil,10
print(a1,a2);

23.unpack返回table所有的参数
例:

function f(a,b,c)
    print(a,b,c);
end
local a = {"a","b","c"};
f(unpack(a));

其中unpack是用c语言实现的,用lua的实现可以表示如下:
例:

function unpack(t,i)
    local i = i or 1;
    if t[i] then
        return t[i],unpack(t,i+1);
    end
end

24.lua函数可使用…来接受可变数量的参数。此时,lua讲函数参数放在一个arg的表中,这个表中还包含了一个表示参数数量的域n,通过遍历变量arg可以获得可变数量的参数的值

25.可以用虚变量_跳过某些函数返回值

26.table排序
例:

network = {
    {name = "grauna",IP = "210.26.30.34"},
    {name = "arraial",IP = "210.26.30.23"},
    {name = "lua",IP = "210,26,30,12"},
    {name = "derain",IP = "210.26.23.20"},
}
table.sort(network,function(a,b) return (a.name < b.name) end);
for k,v in pairs(network) do
    print("this is network : "..k..":"..v.name..":"..v.IP);
end

27.Lua中的函数是带有词法定界的第一类值。第一类值指:在Lua中函数和其他值(数值,字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值。词法定界指:被嵌套的函数可以访问他外部函数中的变量(闭包的实现,然后闭包可以用于实现迭代器)。

28.闭包

function newCounter()
    local i = 0;
    --返回一个匿名函数,此时变量i存储在upvalue中
    return function()
        --i称为外部的局部变量或者upvalue
        i = i + 1;
        return i;
    end
end
c1 = newCounter();
--输出1
print(c1());
--输出2
print(c1());
c2 = newCounter();
--输出1
print(c2());

29.局部函数如果是递归函数的话,最好写一个前置函数声明,否则由于Lua不知道函数是局部函数,Lua回去查找是否有这样的全局函数。
例:

local f = function (n)
    if n == 0 then
        return 1;
    else
        return n * f(n-1);
    end
end

由于Lua编译时遇到fact(n-1)并不知道他是局部函数fact,Lua回去查找是否有这样的全局函数fact.为了解决这个问题我们必须在定义函数以前先声明。

local f;
f = function (n)
    if n == 0 then
        return 1;
    else
        return n * f(n-1);
    end
end

也可以表示为

local f;
function f (n)
    if n == 0 then
        return 1;
    else
        return n * f(n-1);
    end
end
print(f(10));

30.lua中return g(…)这种格式的调用称为尾调用(记住一定是这种格式的,return g(…)+1,都不算是尾调用)
例:

function g()
end
function f()
    return g();
end

例子中f调用g后不会再做任何事情,这种情况下当被调用函数g结束时程序不需要返回到调用者f;所以尾调用之后程序不需要再栈中保留关于调用者的任何信息。一些编译器比如Lua解释器利用这种特性再处理尾调用时不使用额外的栈,我们称这种语言支持正确的尾调用。由于尾调用不需要使用栈空间,那么尾调用递归的层次可以无限制的。例如下面调用不论n为何值不会导致栈溢出。
例:

function f(n)
    if n > 0 then
        return f(n-1);
    end
end

31.迭代器和范性for语句

function list_iter(t)
    local i = 0;
    local n = table.getn(t);
    return function()
        i = i + 1;
        if i <= n then return t[i] end;
    end
end

t = {10,20,30}
local iter = list_iter(t);
while true do
    local element = iter();
    if element == nil then break; end
    print(element);
end

for element in list_iter(t) do
    print(element);
end

function allwords()
    local state = {line = io.read(),pos = 1};
    return allwords_itera,state;
end

function allwords_itera(state)
    while state.line do
        local s,e = string.find(state.line,"%w+",state.pos);
        if s then
            state.pos = e + 1;
            return string.sub(state.line,s,e);
        else
            state.line = io.read();
            state.pos = 1;
        end
    end
    return nil;
end

for word in allwords() do
    print("this is word :"..word);
end

32.dofile,loadfile,dostring,loadstring实现,记住loadstring总在全局环境中编译他的串。

function dofile(filename)
    local f = assert(loadfile(filename));
    return f();
end
loadstring([[print("this is loadstring")]])();
i = 0;
--i只能是全局变量
f = loadstring("i = i + 1");
f();
print(i);
f()
print(i);
--输出nil和 错误信息
print(loadstring("i i"));

33.dofile和require粗略来说功能相同,但是他们的不同点是:require会搜索目录加载文件,require会判断目录是否已经加载,避免重复加载同一文件。由于上述特征,require是lua中加载库的更好的函数。
require的路径是一个模式列表,每一种模式指明一种由虚函数(require的方式)名转化为实文件名的方式,更确切的说,每一种模式是一个包含可选的问号的文件名。匹配的时候lua会先将问号用虚函数名替换,看看是否有这样的文件存在。如果不存在继续用同样的方法用第二个模式匹配。
例:

路径如下时:?;?.lua;c:\windows\?;/user/local/lua/?/?.lua
调用 require "lili"时会试着打开这些文件
lili
lili.lua
c:\windows\lili
/usr/local/lua/lili/lili.lua

也就是lua关心的问题只有分号;,也就是模式之间的分隔符,以及问号,其他的信息(目录分割符,文件扩展名)在路径中定义。
为了确定路径Lua会首先检查全局变量LUA_PATH是否是一个字符串,如果是则默认它是一个路径。否则require检查环境变量LUA_PATH的值,如果两个都失败,require使用固定路径(典型的?;?.lua)
require的另一个功能是避免加载同一个文件两次。lua会保存一张已经加载的文件路径的列表(用table保存)。如果一个加载的文件在表中存在require简单的返回。表中保留加载的文件的虚名,而不是实文件名。所以如果你使用不同的虚文件名require同一个文件两次,将会加载这个文件2次。
例:

require foo
require foo.lua
路径:?;?.lua将会加载foo文件2

我们也可以使用全局变量_LOADED访问文件名列表。这样我们就可以判断一个文件是否被加载过。同样我们也可以使用一个小技巧让require加载一个文件2次。
例:

require "foo"后_LOADED["foo"]的值将会不为nil,我们可以通过将_LOADED["foo"]的值置为nil,从而require "foo"会再次加载该文件

一个路径的模式也可以不包含问号,而只是一个固定路径

?;?.lua;/usr/local/default.lua
这种情况下,require没有匹配的时候,就会使用这个固定路径(当然固定路径要放在最后一位才有意义)。

在require运行一个chunk之前他定义了一个全局变量_REQUIRENAME来保存被require的虚文件名。
例:

我们可以把路径设为"/usr/local/lua/newrequire.lua",这样以后每次调用require都会运行newrequire.lua,这种情况下可以通过使用_REQUIREDNAME的值去实际加载required的文件。

(注意以上_LOADED,_REQUIREDNAME在5.1版本lua中输出均为nil,可能变量已经被抛弃,可以使用package.loaded代替)

34.lua通过支持动态链接库加载c函数可以使用package.loadlib()检查当前版本是否支持动态链接机制
例:

local path = "/usr/local/lua/lib/libluasocket.so";
--package.loadlib的参数是库的绝对路径和初始化函数
print(package.loadlib(path,"luaopen_socket"));
local f = package.loadlib(path,"luaopen_socket");
输出:nil  找不到指定的模块。

    open
说明当前版本是支持动态链接机制的,只是没有找到制定模块。
package.loadlib加载制定的库并链接到lua,但是并没有打开库(也就是没有调用初始化函数),反之他返回初始化函数作为lua的一个函数,这样我们可以直接在lua中调用他们。如果加载动态库或者查找初始化函数出错,那么package.loadlib将返回nil和一段错误信息。

35.抛出错误信息的两种方式:error,assert
例:

print "enter a number:"
n = io.read("*number");
if not n then
    error("invalid input")
end
print "enter a number:"
assert(io.read("*number"),"invalid input");
assert首先会检查第一个参数是否返回错误,如果没有错误,则assert简单的返回,否则assert会以第二个参数抛出错误信息,第二个参数是可选的。

36.捕获异常:pcall在保护模式下调用他的第一个参数并运行,因此可以捕获所有的异常和错误。如果没有错误,pcall返回true和调用返回的任何值,否则返回nil和错误信息。错误信息不一定非要是一个字符串,传递给error的信息都会被pcall返回.当pcall返回错误信息的时候,它已经释放了保存错误发生情况的栈的信息,因此如果我们想得到tracebacks,必须在pcall返回之前获取。Lua提供了xpcall来实现这个功能,xpcall接受两个参数:调用函数和错误处理函数。

local status,err = pcall(function () error({code = 112}) end);
print(status,err.code);
输出:false 112

37.调用debug.traceback可以获取当前的traceback信息。

38.Lua将环境变量本身存储在一个全局变量_G中,且_G._G = _G

for n in pairs(_G) do
    print(n);
end
输出:collectgarbage
getmetatable
(...剩下的输出省略)
function getfield(f)
    local v = _G;
    for w in string.gfind(f,"[%w_]+") do
        v = v[w];
    end
    return v;
end

function setfield(f,v)
    local t = _G;
    for w,d in string.gfind(f,"([%w_]+)(.?)") do
        if d == "." then
            t[w] = t[w] or {};
            t = t[w];
        else
            t[w] = v;
        end
    end
end

setfield("t.x.y",10);
print(t.x.y);
print(getfield("t.x.y"));
--使用rawset绕过__newindex,给_G赋值,但是declare要在setmetatable调用前定义
function declare(name,initval)
    rawset(_G,name,initval or false);
end

setmetatable(_G,{
    __newindex = function(_,n)
        error("attempt to write to undeclared variable "..n,2);
    end,
    __index = function(_,n)
        error("attempt to read undeclared variable "..n,2);
    end,
    })
declare "a";
a = 1;
print(a);
local declaredNames = {};
function declare(name,initval)
    rawset(_G,name,initval);
    declaredNames[name] = true;
end

setmetatable(_G,{
    __newindex = function(t,n,v)
        if not declaredNames[n] then
            error("attempt to write to undeclared var. "..n,2);
        else
            rawset(t,n,v);
        end
    end,
    __index = function(_,n)
        if not declaredNames[n] then
            error("attempt to read undeclared var. "..n,2);
        else
            return nil;
        end
    end,
    })

39.可以使用setfenv函数来改变一个函数的环境。Setfenv接受函数和新的环境作为参数。除了使用函数本身,还可以指定一个数字表示栈顶的活动函数。数字1代表当前函数,数字2代表调用当前函数的函数。

a = 1;
local newgt = {};
setmetatable(newgt,{__index = _G});
--由于使用的是Lua5.3版本,所以用_ENV来代替setfenv
local _ENV = newgt;
a = 10;
print(a);
print(_G.a);
_G.a = 20;
print(_G.a)
--由于使用的是Lua5.3,所以用load来代替loadstring
load([[print(a)]],"tempload","t",_ENV)();

猜你喜欢

转载自blog.csdn.net/SHIYUEDYX/article/details/80436392