Lua 基础知识、数据类型和基本语法

Lua 基础知识、数据类型和基本语法

一、基础知识

特性
  • 轻量级
  • 可拓展
  • 支持面向过程编程和函数式编程
  • 自动内存管理
  • 闭包和多线程
应用场景
  • 游戏开发
  • 独立应用脚本
  • Web 应用脚本
  • 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
  • 安全系统,如入侵检测系统
为什么Lua可以进行热更新?

Lua是使用C写的脚本语言,在运行时读入Lua编写的代码,在解释Lua时不是翻译为机器码,而是使用C代码进行解释,不用开辟可执行权限的内存空间,也不会有新代码执行,执行解释的是用C语言写出来的虚拟机。

二、数据类型

Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。

需要注意的点:

Nil

Lua 中特殊的类型,他只有一个值:nil;一个全局变量没有被赋值以前默认值为 nil;给全局变量负 nil 可以删除该变量。

type 函数的返回值类型是 string,所以与 type 比较时的 nil 应加上双引号
print(type(x) == "nil") --结果为true

Booleans

在控制结构的条件中除了 false 和 nil 为假,其他值都为真。所以 Lua 认为 0 和空串都是真。

要点

  1. 运行时,Lua会自动在string和numbers之间自动进行类型转换,当一个字符串使用算术操作符时, string 就会被转成数字

  2. table中 如下述代码"Hello"、“World”、“Good”、"Bye"是表中的值,在存储时是按照顺序存储的,并且不同于其他脚本语言,Lua是从1开始排序的,因此,使用pairs遍历打印输出时,会先按照顺序输出表的值,然后再按照键值对的键的哈希值打印。

    tab = {"Hello","World",a=1,b=2,z=3,x=10,y=20,"Good","Bye"}
    for k,v in pairs(tab) do
        print(k.."  "..v)
    end
    1  Hello
    2  World
    3  Good
    4  Bye
    x  10
    y  20
    z  3
    b  2
    a  1
    
  3. … 连接符号 ,可以连接字符串类型,也可以连接整形的变量,但是如果直接使用真实的数字要在后面加个空格,因为系统会把 数字… 看出2个浮点 如 1…2 (错误写法) 1 …2 (正确写法).

  4. 类型不同,比较判断也不会相等,如number类型的123不等于string类型的123

  5. 关系运算符中~= 表示不等于,类似其他语言如c的 !=

  6. 逻辑运算符 and ,or ,not 对应 && ,|| , !

  7. 表达式:a and b a为假则返回a 否则返回b, a or b a为真返回a否则返回b ,简单理解and就是先判断a a正确就继续判断b,如果b也正确返回btrue,则if(a and b) 为true ,这实际上也是&&的使用原理一样 ,如果a为假就是false直接返回a if(a and b) 就是false了 。 or 同理 ||

  8. 局部变量 用local修饰声明 ,内存在栈上,在一个函数,代码块{ }内 函数,代码块结束,内存自动释放

  9. 全局变量在堆上,可以随时创建,程序结束,内存自动释放

  10. lua中没有 do … while() 取而代之的是 repeat…until

  11. 控制语句上,不需要写 () {} {指代 :then } 指代 : end

  12. 循环结构 while do end ,里面不能写() 以及 ++ – += 类似的运算符

  13. 函数的返回值和其他语言一样可以返回个值,变量。但是不同的是可以同时返回多个变量,进行多个赋值

  14. print()打印会默认换行

  15. #号数组是计算数组容器table的下标个数,lua的数组容器下标从1开始计算递增,字典不包括key元素

  16. 有两种遍历结构pairs ,ipairs ,第一个遍历所有元素,第二个只遍历没有key类型的元素(不遍历字典),不能返回nil

  17. 判断表是否为空:

table = {}
if next(table_a) == nil then
end

三、控制语句与循环

1.if:
a = 1
if  a > 0 then
    print("大于")		-- true
else
    print("小于")
end
2.while循环
--while循环
sum = 0
count = 1
while count <= 5 do
    sum = sum + count
    count = count + 1 
end
print(sum) -- 1 2 3 4 5 
3.for循环
--for
for num = 1,10,2 do
    print(num) -- 1 3 5 7 9
end 

for num2 = 10 ,0, -2 do
    print(num2) -- 10 8 6 4 2 0
end
4.repeat…until 循环

​ lua中没有 do … while() 取而代之的是 repeat…until

5.break 语句

​ Lua 编程语言 break 语句插入在循环体中,用于退出当前循环或语句,并开始脚本执行紧接着的语句。

6.如何实现continue

​ 在循环内套一个repeat … until true,再将想用continue的地方写成break。

for i = 1, 10 do
    repeat
        if i == 5 then
            break
        end
        print(i)
    until true
end

四、函数

一个 Lua程序既可以调用Lua语言编写的函数,也可以调用C语言(或者宿主程序使用的其他任意语言)编写的函数。

一般来说,我们选择使用C语言编写的函数来实现对性能要求更高,或不容易直接通过Lua语言进行操作的操作系统机制等。

例如,Lua语言标准库中所有的函数就都是使用C语言编写的。不过,无论一个函数是用Lua语言编写的还是用C语言编写的,在调用它们时都没有任何区别。

Lua语言也为面向对象风格的调用( object-oriented call)提供了一种特殊的语法,即冒号操作符。

  1. function 0:foo(x) end 表示定义对象o的foo方法
  2. o:foo(x)的表达式意为调用对象o的foo方法。
  3. 冒号的作用是在一个方法调用中增加一个额外的实参,或在方法的定义中增加一个额外的隐藏形参。
  4. 冒号只是一种语法机制,虽然很便利,但没有引入任何新的东西。我们可以使用点分语法来定义一个函数,然后用冒号语法调用它,反之亦然,只要能够正确地处理好额外的参数即可:
  • 函数定义实例

    o = {x=0,y=0}
    function o:GetX()
        print(self.x)       -- self:类似于this,表示o(对操作的接收者)
    end
    o:GetX()        -- 0
    
    --[[ 函数返回两个值的最大值 --]]
    function max(num1, num2)
    
       if (num1 > num2) then
          result = num1;
       else
          result = num2;
       end
    
       return result;
    end
    -- 调用函数
    print("两值比较最大值为 ",max(10,4))
    print("两值比较最大值为 ",max(5,6))
    
  • 多返回值

    Lua函数可以返回多个结果值,比如string.find,其返回匹配串"开始和结束的下标"(如果不存在匹配串返回nil)

    local s, e = string.find("www.runoob.com", "runoob") print(s, e)
    

    如果只想接收第二个值,可以使用 __

    local _, e = string.find("www.runoob.com", "runoob") > print(e)
    
  • 可变参数

    Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 表示函数有可变的参数。

function average(...)
   result = 0
   local arg={...}
   for i,v in ipairs(arg) do
      result = result + v
   end
   print("总共传入 " .. select("#",...) .. " 个数")
   return result/select("#",...)
end

print("平均值为",average(10,5,3,4,5,6))

​ 固定参数+可变参数

function fwrite(fmt, ...)  ---> 固定的参数fmt
    return io.write(string.format(fmt, ...))    
end

fwrite("runoob\n")       --->fmt = "runoob", 没有变长参数。  
fwrite("%d%d\n", 1, 2)   --->fmt = "%d%d", 变长参数为 1 和 2
  • select (index, ···)

    如果index是一个数字,返回参数number index之后的所有参数;

    一个负数从末尾开始索引(-1是最后一个参数)。

    否则,index必须是字符串“#”,而select返回它接收到的额外参数的总数。

五、table 数组,字典 ,混写

在 Lua语言中,数组索引按照惯例是从1开始的(不像C语言从0开始),Lua语言中的其他很多机制也遵循这个惯例。

只有在表中不存在空洞( hole)时(即所有元素均不为nil ),且表的索引是连续的,才有效,此时我们把这种所有元素都不为nil 的数组称为数组 sequence )。。

--数组:
t1 = {"星期一","星期二","星期三","星期四"}
print(t1[3])		--星期三
--字典:key必须是变量,不能是数字
t2 = {name="Young",age = 23,sex = "girl"}
print(t2.name)		-- Young
print(t2["name"])	-- Young
t2.sex = "boy"
print(t2.sex)		--boy
--混写
t3 = {name = "AK","星期一",age = 35,"星期二"}
print(t3.name) --AK 
print(t3[1])  --星期一

六、table.unpack()

返回列表中的元素。 这个函数等价于return list[i], list[i+1], ···, list[j] i 默认为 1 ,j 默认为 #list

  • 多重返回值还涉及一个特殊的函数table.unpack(),该函数的****参数是一个数组,返回值为数组内的所有元素****
print(table.unpack{10, 20, 30})     --  10   20   30
 
a, b = table.unpack{10, 20, 30}
print(a, b)    --  10   20  
  • table.pack():把参数列表转换为Lua语言中的一个列表(表)
  • table.unpack():把列表(表)转换为一组值,进而可以作为另一个函数的参数被使用
  • 泛型调用机制
    unpack()函数的重要用途之一体现在泛型调用机制中;泛型调用机制允许我们动态地调用具有任意参数的任意函数
    例如,在ISO C中,我们无法编写泛型调用的代码,只能声明可变长参数的函数(使用stdarg.h)或使用函数指针来调用不同的函数;但是,我们仍然不能调用具有可变数量参数的函数,因为C语言中的每一个函数调用的实参个数是固定的,并且每个实参的类型也是固定的
    而在Lua中,却可以做到这一点,如果我们想通过数组a传入可变参数来调用函数f,那么写成下面的代码,table.unpack()函数会返回数组a的所有元素,然后作为f的参数f(table.unpack(a))
print(string.find("hello", "ll"))		--  3     4  
-- 上面的代码可以改写为下面的样子
f = string.find
a = {"hello", "ll"}
 
print(f(table.unpack(a)))		--  3     4 

七、正确的尾调用

  • Lua语言中有关函数的另一个有趣的特性是,Lua原因是支持尾调用消除的。这意味着Lua可以正确地尾递归,虽然尾递归调用消除的概念并没有直接涉及递归
    尾调用也就是递归

  • 尾调用
    尾调用是被当作函数调用使用的跳转,当一个函数的最后一个动作是调用另一个函数而没有进行其它工作时,就形成了尾调用
    例如,下面的代码中对函数g()的调用就是尾调用

    function f(x)
        x = x + 1
        return g(x)
    end
    

    尾调用消除

    • 在上面的代码中,当函数f()调用完g()之后,f()不再需要进行其它的工作。这样,当被调用的函数执行结束后,程序就不再需要返回最初的调用者。因此,在尾调用之后,程序也就不需要在调用栈中保存有关调用函数的任何信息。当g()返回时,程序的执行路径会直接返回到调用f()的位置
    • 在一些语言的实现中,例如Lua语言解释器中,就利用了这个特点,使得在进行尾调用时不使用任何额外的栈空间,我们将这种实现称为“尾调用消除”
      由于尾调用不
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值