Lua学习(一)基础语法


文章目录


  • 一、Lua介绍
  • 二、基础语法以及使用的细节
  • 三、学习总结



前言

         因为Lua技术能够很好的支持游戏热更新,因此在游戏开发过程中使用广泛。这里参考电子工业出版社出版的由Robertp Ierusalimschy(巴西)编写,周惟迪先生翻译的Lua程序设计(第二版)进行自主学习。


一、Lua是什么?来认识一下

(1)Lua语言设计初衷

            Lua语言起初是想设计成能与C语言或者其他常用语言编写的软件相互集成。Lua作为一门简单小巧的语言,一部分原因是因为不准备做C语言已经做的很好的方面(例:C语言超高的性能、底层操作能力以及与第三方软件之间的接口)。Lua提供的相对于硬件高层抽象、动态结构、无冗余(No Redundancy)、建议的测试和调试这些特性是C语言不擅长的。Lua还实现了一个安全的运行环境、一套自动内存管理机制、优秀的字符串处理能力和动态大小数据的处理功能。

(2)Lua语言的可扩展性

            Lua语言中大部分基础功能是通过外部库进行实现的。其中的许多特性体现出他的可扩展性:

           1、动态类型:为多态提供了支持

           2、自动内存管理:简化了接口,从而无需决定谁分配内存、谁释放内存以及如何处理溢出等。

           3、高阶(Higher-order)函数和匿名函数:允许实现更高层的参数化,能使函数变得更加通用。

(3)Lua语言的特点

           Lua语言也是一门“胶水语言”。支持基于组件的软件开发方法。不仅可以用于黏合组件还可以用于适配组件或者改造组件,甚至创建出一个全新的组件。

          简易性:Lua是一种简单、小巧的语言。完整的Lua发布版可以很轻松的存放在一张软盘中。

          高效:独立测评结果显示Lua是脚本(解释型的)语言领域中最快的语言之一。

          可移植性:Lua不仅可以同时运行在Windows和UNIX平台上,可以运行在任何平台上。Lua不使用条件编译对不同平台进行特殊处理,只依赖于ANSI(ISO)C标准来编写Lua的实现代码。

   注:关于编译型语言与解释型语言认识与区分

         编译型语言(通篇翻译>>生成翻译后文件>>执行翻译后文件):C  C++  

                  优点:执行效率快

                  不足:移植性差(不跨平台)

         解释型语言(翻译一行执行一行,不生成解释性文件):Lua  Javascript   php  python  

                  优点:跨平台

                  不足:执行效率稍微慢(由于硬件现在不断进步,所以不是很明显)

          其中Java不属于上述两种(oak语言):

              java有一个jvm虚拟机,.java文件通过javac先编译成.class文件,再通过java虚拟机jvm解释执行(跨平台性)

二、:Lua基础语法与使用的细节问题

          在学习Lua语言时用到的编译器是SublimeText,因为它简洁,执行起来比较快。缺点是只有少部分提示,考验代码编写时的基础语法英文。SublimeText分为两个版本(2和3),按下Ctrl+B键运行。

在2中使用要搭建Lua环境(有时间会写一下如何搭建使用),而3中集成了Lua语言的功能,不需要搭建就可以直接使用。

(1)Lua语法特点

          首先给人的感觉就是简洁,没有过多冗余的”{}“和”;“,区别于其他语言(如C,C#等)。

          Lua中的标识符可以是由任意字母、数字、下划线构成的字符串,不能以数字开头。避免使用下划线开头加一个或多个大写字母的标识符,Lua将这类标识符保留用作特殊用途。

          Lua区分大小写,用”--“行注释。”--[[ 代码块 ]]“块注释。变量默认声明为全局变量。

          访问未初始化的变量不会引发错误,访问结果时nil.

          Lua中有8基础类型:nil(空)、boolean(布尔)、number(数字)、string(字符串)、userdata(自定义类型)、function(函数)、thread(线程)和table(表)。

(2)使用Lua语言的一些代码细节

print("This is the first lua program")
if true then 
    print("Hello")
end
--这是一个注释
a= nil
--[[这是一个多行注释
这是一个多行注释
这是一个多行注释
--]] 
print(type("hello"))
print(type(10.3)) 
print(type(nil))
print(type(true))
print(type(type(10.3)))
a={x=3,y=6}
print(type(a))

a ="one string"
b=string.gsub(a,"one","another")
print(b)

          字符串的替换,输出b的值为another string

a="zhang"
b="san"
--local表示局部变量
local sum =a.." "..b
print(sum)
--遇到算数运算符,string与number之间自动转换
a=10
print(a+"1")

print(a.."1")
--不加空格会报错,系统认为第一个.表示小数点
print(10 ..1)

print(tonumber("10"))

输出结果:

lua语言做界面 lua语言入门_lua

关系运算符:”~“表示非,A and B简单理解就是返回其中第一个false值/nil值,A B全为真返回A; A or B 返回第一个真值,全为false值/nil值时返回第一个。

if 10~="10" then
    print("equal")
end

print(4 and 5)
print(nil and 13)
print(false and nil)
print(false and 13)
print(4 or 5)
print(false or 5)

输出结果:

lua语言做界面 lua语言入门_编程语言_02

 --求两个数中较大值
function max(a,b)
    if a>b then
        return a
    else 
        return b
    end
    -- body
end
print("Max:"..max(2,1))
--加法函数
function Add(a,b)
    -- body
    return a+10,b+10
end
m,n=Add(1,2)
print(m,n)

--斐波那契数列
function fabric(n)
    if n==1 or n==2 then
        return 1
    else 
       return fabric(n-1)+fabric(n-2)
    end
    -- body
end
print(fabric(3))

输出结果分别是:Max:2           11,12             2

--table的数组形式
local days ={"A","B","C","D"}
print(#days)--只能用于标准的数组格式
print(days[1])
print(table.maxn(days))

--遍历的两种形式
for i=1,#days do
    print(days[i])
end

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

--字典形式
local person = {"January","Februray",name="zhangsan",[4]="March",age=20,sex=true}
print(person["name"])
print(#person)
print(table.maxn(person))
person.age=25--person["age"]=50
person.country="China"
--ipairs 只能用于数组形式 pairs都可以 数组字典混合ipairs只遍历数组
--ipairs顺序遍历数组,不能有间隔,[3]="March"可以显示[4]="March"不能显示
for k,v in ipairs(person) do
    print(k,v)
end

#数组名等价于table.maxn(数组名)   但是无法用来表示字典形式的长度

字典中访问某个键时可以通过字典名.键名或字典名[”键名“]两种方式访问

关于table库中常用的一些函数:

t={1,2,3}
--头插法
table.insert(t,1,0)
--尾插法
table.insert(t,#t+1,4)
--删除
table.remove(t,2)
table.insert(t,1)
--排序
table.sort(t)
for k,v in pairs(t) do
    print(k,v)
end
spring ={"众里寻他千百度","慕然回首","那人却在灯火阑珊处"}
print('逗号链接:',table.concat(spring,","))
--逗号链接:    众里寻他千百度,慕然回首,那人却在灯火阑珊处
print('逗号链接从1位置开始,2位置结束:',table.concat(spring,",",1,2))
--逗号链接从1位置开始,2位置结束:    众里寻他千百度,慕然回首
print('换行显示,从1位置到3位置:\n',table.concat(spring,"\n",1,3))
--    众里寻他千百度
--慕然回首
--那人却在灯火阑珊处
num={1,2,3,4,5,6}
print('大小比较:',table.concat(num,"<"))
--大小比较:    1<2<3<4<5<6

apple={"a","p",[5]="e"}
--返回table中所有元素下标的最大值
print(table.maxn(apple))
print(#apple)
--得到table的长度
print(table.getn(apple))
ta={1,2,[24]=3}
print(table.maxn(ta))

关于Math数学库中常用的函数介绍:

--随机数种子
math.randomseed(tostring(os.time()):reverse():sub(1,6))
print(math.random(1,100))
print(math.random(1,100))
print(math.random(1,100))
print("_______________________")
--圆周率
print(math.pi)
--弧度转角度
print(math.deg(3.14))
--去尾5
print(math.floor(5.4))
--进一6
print(math.ceil(5.4))
 

关于上述代码中随机数这块我要解释一下:

        直接使用os.time系统时间设置随机数的时间种子时,是默认一秒执行一次,因此在一秒执行很多次是很容易的,会出现随机数固定而不在随机,读者可以将print(math.random(1,100))这句代码放到循环体中进行尝试。

math.randomseed(tostring(os.time()):reverse():sub(1,6))用这句代码将时间设为每毫秒执行一次,达到随机数的效果。

关于函数的问题:

print("______________________闭合函数_____________________")
--闭合函数
function count( ... )
    -- body
    local i=0
    return function ( ... )
        -- body
        i=i+1
        return i
    end
end
local func=count()--返回的是一个函数而不是值
print(type(func))
print(func())
print(func())

输出结果:function    1      2

print("______________________非全局函数_____________________")

--非全局函数
function A( ... )
    -- body
end
--等价于
local B=function ( ... )
    -- body
    print("func")
end
B()
--[[
--遍历全局变量表
for k,v in pairs(_G) do
    print(k,v)
end
]]
local eat
local drink
eat=function ( ... )
    -- body
    print("eat");
    return drink()
end
drink=function ( ... )
    -- body
    print("drink")
end
eat()

输出结果:func    eat      drink

在这里要注意:

local function eat()

          print("eat")

          return drink()

end

local function drink()

          print("drink")

end


   eat函数里要调用drink函数。但是要注意Lua是解释型语言,逐句解释运行。


   在运行的时候,drink函数是通不过的,因为这个时候drink函数未定义,换句话说,drink变量并不存在。


关于尾调用问题:

          一个函数的调用是另一个函数的最后一个动作时,这个调用就称之为尾调用。比如这样的函数:


     

function eat()
 
                  return drink() 

 
                  
  end


          当eat函数调用完drink函数之后,就没有其他事情要做了,所以,调用drink函数,就属于尾 调用。像下面的就不属于尾调用:


function eat() 
 
                  return drink()+1 
 
                  end


          因为调用完drink函数之后,还要取得drink的返回值,然后进行一次加法操作,这就不符合 定义了。


尾调用有什么好处?


          尾调用的时候,该函数也就意味着结束了,不需要保存任何关于该函数的栈信息, 因此可以拥有无数嵌套尾调用。尾调用主要用来实现状态机等操作。


关于迭代器:

print("_____________________迭代器______________________")
--迭代器
function DieDaiQi(t)
    local i=0
    return function()
        -- body
        i=i+1
        return t[i]
    end
    -- body
end
t={"A","B","C","D"}
local iter=DieDaiQi(t)
while true do
    local value=iter()
    if    value==nil then
        break
    end
    print(value)
end
for value in DieDaiQi(t) do
    print(value)
end

function DieDaiQiTwo(t)
    local i=0
    return function ()
        i=i+1
        if    i > #t then
            return nil
            end
        return i,t[i]
       end
end
for k,v in DieDaiQiTwo(t) do
    print(k..","..v)
end

输出结果:

lua语言做界面 lua语言入门_编程语言_03


三、学习总结

         主要是初识Lua语言,结合之前学过的C语言、Java语言、C#语言进行对比,很容易发现Lua语言简洁便捷,代码简单,同时出错时能直接显示具体的行数。知识点比较繁琐,杂乱,不过整理后能发现代码的语法跟其他语言是大同小异的。