Lua学习笔记Day2-Lua语法、值与类型、表达式、语句、函数

Lua学习笔记Day2-Lua语法、值与类型、表达式、语句、函数

目录

  • Lua是什么?
  • Lua语法
  • Lua类型与值
  • Lua表达式
  • Lua语句
  • Lua函数
  • Lua深入函数

本文内容来自《Lua程序设计》

Lua是什么?

Lua是一门简单小巧的脚本语言,能与其他语言相辅相成。Lua依靠别的语言实现实现这些语言的功能,Lua的其他特性是别的语言不擅长的,为此Lua实现了一个安全的运行环境、一套自动内存管理机制、优秀的字符串处理能力和动态数据的处理能力。

Lua可以看做一门功能齐全的胶水语言。Lua的特性:
可扩展性。Lua可以集成到其他语言甚至脚本语言中,用来扩展程序,一个应用程序可以通过Lua反复修改。
简单小巧。Lua具有的概念并不多,但都很有用。
高效。Lua是解释型脚本语言中最快的。
可抑制性。Lua可以运行在任何平台上,因为Lua依赖于C标准。

Lua语法

Lua保留字:
and break do if else elseif
end false for function 
in local nil not or
repeat return then true until while
Lua是有大小写之分的
全局变量
b = 10 
b即是全局变量,没必要将全局变量删除,如果一定要删除,就b = nil

Lua类型与值

  • 普通类型

    Lua有八种基础类型:nil、boolean、number、string、userdata(自定义数据)、function、thread、table。
    任何变量都可以包含任何类型的值。
    Lua将0和空字符串也视为”真”。
    number类型表示实数(双精度浮点数)。

  • string

    Lua完全采用8位编码,可以将任何二进制数据存储到一个字符串中。Lua也不能直接修改字符串,而是创建一个新的字符串。Lua字符串可有单引号或双引号包括。
    Lua的字符串是由内存自动管理的,无需担心字符串的分配和释放。
    Lua不会转译[[和]]之间的任何内容。
    ..是字符串连接操作符,print(10 ..20)–>1020。注意10后面有空格。
    字符串转数字:tonumber(string)。
    数字转字符串:tostring(int)或int ..”“。
    ‘#’号+string 代表字符串长度。

  • table

    table表实现了”关联数组”,关联数组是一种有特殊的索引方式的数组,不仅可以通过整数索引它还可以使用字符串或其他类型的值。table没有固定大小,可以动态地添加任何数量的元素。table是Lua仅有的数据结构机制。
    table不是值也不是变量,是一种对象。程序仅持有一个对他们的引用,table的创建是通过”构造表达式”完成的,最简单的方式是{}。
    a = {}
    b = a
    a = nil 只有b还在引用table
    b = nil 再也没有table的引用了
    当一个程序再也没有对table的引用时,Lua的垃圾回收器(GC)最终会删除该table,并复用其内存。全局变量就是存放在一个普通的表中。
    print(a[#a]) 打印table a的最后一个值
    a[#a] = nil 删除最后一个值
    a = {}
    a[100] = 1
    print(#a) –> 0 因为#碰到nil就结束
    print(table.maxn(a)) –> 100

  • function

    function函数
    Lua的function也是一种类型,可以储存在变量中,可以通过变量传递给其他函数,也可以作为返回值。
    Lua可以调用Lua编写的函数也可以调用C语言编写的函数。

  • userdata

    userdata类型可以将任何C语言数据存储到Lua变量中,userdata没有太多操作,只能进行赋值和相等性测试。

Lua表达式

表达式用于表示一个值。
  • 算术操作符

    算术操作符:+-*/^% -负号
    关系操作符:< > <= >= == ~=。如果两个值类型不相同就一定不相等。nil只于nil相等。对于table、userdata、函数,只有他们的引用相同时才相等。

  • 逻辑操作符

    and or not,所有逻辑操作符将false和nil视为假,其余视为真。
    and:第一个操作数为假返回第一个,否则返回第二个。
    or:第一个操作数为真返回第一个,否则返回第二个。
    x = x or v x为假或空时对x赋一个v
    max = (x>y) and x or y 求x y的最大值。
    操作符not永远只返回true或false

  • 优先级

    ^ 右结合
    not # - 其余都是左结合
    乘除求余
    加减
    .. 右结合
    < > <= >= ~= ==
    and
    or

    table构造式:a = {}
    a = {x=10, y=20} 等价于 a = {};a.x = 10;a.y = 20

Lua语句

语句包括赋值、控制结构和过程调用。
  • 多重赋值

    Lua允许多重赋值:a,b = 10,2*x。x,y = y,x交换x,y的值。
    多重赋值还用于接收多个函数返回值。

  • 局部变量

    局部变量:i = 10是全局变量,local j = 10是局部变量。
    局部变量仅作用于声明它的块。块是一个控制结构的执行体、函数的执行体、程序块。
    显式的定义一个块:do end。尽可能的用局部变量,它可以避免将一些无用的名称引入全局环境,而且访问的更快,最后随着作用域的结束而消失。
    local foo = foo。用局部变量foo保存全局变量foo,可以用来加速当前作用域对foo的访问。

  • 控制结构

    if 条件 then 
    elseif then
    else
    end
    Lua不支持switch

    while 条件 do
    end

    repeat
    until 条件

    for var = exp1,exp2,exp3 do
        break
    end
    var是局部变量,exp1是起始值,exp2是结束值,exp3是步长

    for i,v in ipairs(array) do
        break
    end
    i是索引值,v是对应于该索引的数组元素值,array是数组

    for k in pairs(table) do
        break
    end
    k是控制变量,table是表。

    for line in io.lines() do
    end

    do return end用于显式的跳过一段代码

Lua函数

Lua函数是对语句和表达式进行抽象的主要机制。当函数的参数只有一个并且参数是字符串或table表时,函数的括号可以不写。
  • 多重返回值

    多个参数:

    function f(a,b) return a or b end
    f(3) --> a = 3,b = nil
    f(3,4) --> a = 3,b = 4
    f(3,4,5) --> a = 3,b = 4

    多返回值:return m1,m2即可
    function foo0() end 无返回值
    function foo1() return”a” end 返回一个
    function foo2() return”a”,”b” end 返回两个
    print(foo2(),1) 结果是a 1,Lua会将foo2返回值数量调到1个(print()函数的参数个数)。
    t = {foo2()} –> t = {“a”, “b”}
    不过t = {foo(),foo2(),4} –> t = {nil,”a”,4} foo2()仍只有一个返回值。即函数调用不是表达式最后一个元素时只产生一个值。
    return foo2()也会返回foo2()的所有返回值。但return (foo2()) –>只返回一个值。

    unpack函数,接收一个数组从下标1开始返回该数组的所有元素。比如a = {“hello”,”ll”} string.find(unpack(a))

  • 变长参数

    function add(…) …就代表不同数量的实参,这个参数就叫变长参数,访问时仍用…。
    …的行为类似具有多重返回值的函数,返回的是当前函数所有的变长参数,如local a,b = …。
    访问变长参数就像访问table一样,但有可能其中有nil,所以要用到select:

    for i=1,select('#',...) do
    local arg = select(i,...)
    end

    select(‘#’,…) 得到…的长度,包括nil。select(i,…)得到第i个参数。

  • 具名参数

    Lua中的参数传递是具有位置性的。我们可以将参数组织到一个table中,把table作为唯一实参传递给函数。

    function rename(arg)
    rueturn os.rename(arg.old,arg.new)
    end

    如果一个函数拥有大量的参数,而且大部分参数可选的情况下,这种风格很有用。函数内部会检查必填参数,或为其他参数添加默认值。

Lua深入函数

函数是第一值类型,即函数和其他传统变量具有相同的权利。函数可以储存到局部变量或者全局变量或table。在Lua中讨论函数时,实际在讨论持有某函数的变量。

定义一个函数其实就是一条赋值语句:
function foo(x) return x end
foo = function(x) return x end
匿名函数:function(x)<body>end,不用变量接收就是一个匿名函数。应用:比如table.sort()函数:
table.sort(network,function(a,b) return(a.name < b.name) end) 将表network按name从小到大排序。
像sort()这种接收一个函数作为参数就是一个高级函数。
  • 词法域

    词法域:将一个函数写在另一个函数之内,那么内部函数可以访问外部函数中的局部变量。
    闭合函数:一个闭合函数就是一个函数加上所要访问的所有非局部变量。普通函数本身就是一个闭合函数。

    function cc()
    local i = 0
    return function()
        i = i + 1 --匿名函数内的变量既不是全局又不是局部
        return i
        end
    end
    c = cc()
    c1 = cc()
    print(c()) --> 1 
    print(c()) --> 2 
    print(c1()) --> 1 

    这种情况应用在回调函数中十分方便,也可以用来重定义函数。这种技术可以创建一个安全的运行环境,即”沙盒”,来执行不受信任的代码(网上接收到的代码)。
    比如把math.sin参数变为角度

    local oldSin = math.sin
    local k = math.pi/180
    math.sin = function(x)
        return oldSin(x*k) --调用原来的sin
        end
    end
  • 非全局的函数

    将函数储存在table中。将函数储存到局部table中就得到了一个局部函数,这个函数只能在某个作用域内使用。因为Lua将程序块作为一个函数来处理的,所以一个程序块声明的函数就是局部函数,局部函数在程序块中可见,词法域确保程序包中其他函数可以使用这些局部函数。
    储存到表中:

    Lib  = {
    foo = function(x,y) return x+y end
    goo = function(x,y) return x-y end
    } 也可以:
    Lib = {}
    function Lib.foo(x,y) return x+y end
    function Lib.goo(x,y) return x-y end
    局部函数的定义:
    Local function f(<参数>)
        <函数体>
    end
  • 尾调用

    当一个函数调用是另一个函数的最后一个动作,如:function f(x) return g(x) end。Lua的尾调用不会消耗任何栈空间。
    function foo(n)
    if n>0 then return foo(n-1) end
    end
    调用这个函数时,传入任何参数都不会造成栈溢出。
    尾调用的用途就是编写状态机,一个函数就是一个状态,改变状态就是goto到另一个函数。

  • 迭代器与泛型for

    所谓的迭代器就是一种可以遍历一种集合中所有元素的机制。Lua把迭代器表示为函数,每次调用函数就返回集合的下一个元素。闭合函数为这种情况提供了支持。

    function value(t)
        local i = 0 
        return function() i=i+1 return t[i] end
    end
    调用:
    t = {10,20,30}
    iter = value(t)
    while true do
        local ele = iter()
        if(ele == nil) then break end
        print(ele)
    end

    大部分情况下我们不需要写value(t)这种迭代器工厂。因为上述迭代器每次循环都会创建新的闭合函数。

    泛型for

    for var-list in exp-list do
        <函数体>
    end

    var-list是变量名列表,第一个元素是控制变量,exp-list是表达式即对迭代器工厂的调用。for先对in后的表达式求值,返回3个值供for保存:迭代器函数、恒定状态、控制变量的初始值。这类似于多重赋值。然后,for会以恒定状态和控制变量来调用迭代器函数,然后将迭代器函数返回值赋予变量列表中的变量,如果返回值为nil则结束循环。

  • 无状态迭代器

    无状态迭代器不保存任何状态的迭代器,我们可以在多个循环中使用同一个无状态迭代器,避免创建闭合函数的开销。典型应用是ipairs和pairs。

  • 具有复杂状态的迭代器

    通常迭代器需要保存许多状态,简单的方法是使用闭合函数,或者把迭代器所需的所有状态打包为table,保存在恒定状态中。这样一个迭代器可以通过table保存任意个数据了。但闭合函数实现迭代器更加高效。我们可以用协同实现迭代器,功能最强但有一定开销。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值