Lua 学习之基础篇十<Lua 常见的语法规则>

下面讲一些lua 常见的用法和规则,可以为学习理解lua带来帮助。

1. if判断

lua把 nil 和false 视为“假”,其他都为“真”

2. 逻辑运算符 and or

lua的and or 可以用来构成三元表达式,如下:

> = 1 == 1 and 1 or 2
1

但如果是这样写,就不是你想要的结果了:

> = 1 == 1 and false or true
true

这是因为,and 运算符判定 false不成立,就继续执行了 or 运算符的结果(nil和false lua都认为为假)
如果你一定要返回 true 或 false,要这么写:

> = ( 1 == 1 and {false} or {true} )[1]
false

3. local变量声明

local var1=1,var2
以上 ,var1和var2的作用域不同,var1是所在作用域的变量,var2可能是全局变量。实际上述命令解释后为 var1 取 "1,var2" 组成的值第一个值,类似 local var1 = ...
请注意变量的声明,如果不确定,就老老实实依依赋值。

local var1
local var2=1
print(var1)  --nil
print(var2)  --1
print("=====")
local var3 =1,var4
print(var3) --1
print(var4) --nil
print("=====")
local  var5, var6=1
print(var5) --1    ->是不是很奇怪-  -、这里的var5竟然是1
print(var6) --nil

4. table是否为空

if a == {} then

结果是false,这是一个逻辑错误,实际比较table a的内存地址和一个匿名table的是否相同

正确的写法是:

if next(a) == nil then

5. 多个变量赋值

name,name = 1,2

那name等于多少呢?

实际上name值为1,可以写个小例子 a,b = 2,3,4打印就可以看到了。a=2,b=3

6. table的key规则

t[name]与t["name"], t.name

第一种和后两种是不同的,第一种会根据取name的值做key,后两种以 "name"做key。这种情况还有:
t = {[name] = 1}

t = {name = 1}
t = {["name"] = 1}

7. table的长度

取得 table 长度最常用的做法是 #table,如下:

> t = {1,2,3}
> #t
3

但 # 操作符也是有局限的,不支援数组以外的对象计算,所以要谨记

> t = { 10, n = 20, 30, 40 }
> #t
3 --长度是4,所以,要采用其他方式判定长度

另外,通过把元素设 nil 无法改变 #table 的结果(除非是数组最后一个元素);而 table.remove 则可以立即更新 #table 的结果

t ={1,2,3}
t[1]=nil
print(#t) --3

table.remove(t,1)
print(#t) --2

8. table引用问题

将一个table复制给另外一个table,修改这个新的table值会影响原来的table,但通过clone可以改变这一行为

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

9. 函数返回值

function f123() 
    return 1, 2, 3
 end
function f456()
     return 4, 5, 6
 end
 print(f123())  --1 2 3
 print(f456())  --4 5 6

 print(f123(), f456()) -- 1 4 5 6
 print(f456(),1) --4 1

如果函数不是处于列的最后一个,只返回一个值

10.浮点数问题

这是浮点数都会有的精度丢失问题,lua也有这个问题。再看下整数与浮点数的比较

> =10==10.00000000000000000
true
> =10==10.00000000000000001
true
> =10==10.00000000000000000
true
> =10==9.999999999999999999
true

所以,这边测试了一下,lua 的浮点数会精确到15位,所以在比较精确的比较之前确认好精度在进行比较

11. 冒号语法

冒号语法可以用来定义函数, 这样的话,函数会有一个隐式的形参 self。

写法如下:
? function t:f (params) body end
冒号语法实际上是一种语法糖,等效于:
? t.f = function (self, params) body end

local t={a=123}

function t.f1(self, p)
    print(self.a, p) --self.a 访问t中a的值
end

function t:f2(p)
    print(self.a, p)
end

t:f1(1)
t.f1(t,1)
t:f2(1)
t.f2(t,1)

以上几个结果都是 123 1
这里,通过冒号方式调用函数不需要加入self参数,而点号则需要。

12. 函数闭包

当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。

function fn()
    local i = 0
    return function()     -- 注意这里是返回函数的地址,不是执行
       i = i + 1
        return i
    end
end
 
c1 = fn()           -- 接收函数返回的地址
print(c1())  --> 1          --c1()才表示执行 ,i 此时为0
print(c1())  --> 2          --继续执行函数体 此时i =1上次执行的结果

如上,调用c1()时,fn函数明显已经返回,lua闭包闭包思想正确处理这种情况:

  • 我们称i为从c1的外部局部变量(external local variable)或者upvalue。
  • 简单的说,闭包是一个函数以及它的upvalues

如果我们再次调用fn,将创建一个新的局部变量i:

c2 = fn()
print(c2())  --> 1
print(c1())  --> 3
print(c2())  --> 2

13. 函数尾调用

  • 尾调用是一种类似在函数结尾的goto调用。
  • 当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用。
function f(x)
    return g(x)  -- 类似于goto g(x)函数的地址
end
  • 尾调用不需要使用栈空间,因此尾调用递归的层次可以无限制的。

例如下面调用不论n为何值不会导致栈溢出。

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

需要注意的是:必须明确什么是尾调用。
一些调用者函数调用其他函数后也没有做其他的事情但不属于尾调用。比如:

function f (x)
    g(x)
    return
end

上面这个例子中f在调用g后,不得不丢弃g地返回值,所以不是尾调用,同样的下面几个例子也不时尾调用:

return g(x) + 1      -- 还需+1
return x or g(x)     -- 还需比较
return (g(x))        -- 还需调整为一个返回值

相关推荐