lua 基础教程

一、lua安装

linux:

lua官网

执行上图命令+make install

lua会安装到/usr/local下,你也可以修改Makefile中的INSTALL_TOP来修改安装的根路径,

注意将lua所在目录添加至PATH

lua安装内容包含如下:

测试:

交互式:

脚本:

二、基本语法

  1. 注释

print("hi")
-- 单行注释

--[[
多行注释
]]--
  1. 标识符

标识符由字母、数字、下划线 组成,只能以下划线和字母开头,不要以下划线+大写字母组成标识符。

  1. 全局变量

没有赋值的变量为nil

print(a)
a=1
print(a)
a=nil
print(a)

三、数据类型

  1. 数据类型nil

没有任何有效值,就是一个nil。

nil由删除的变量,nil的类型为'nil'

-- 定义一个table,相当于map
myTab = {key1 = "value1", key2 = "value2"}
for k,v in pairs(myTab) do
    print(k.."-"..v) end

print("删除key1")
myTab.key1 = nil
for k,v in pairs(myTab) do
    print(k.."-"..v) end

print(x)
print(x == nil)
print(type(x) == "nil")
  1. 数据类型boolean

lua中只有false和nil 为false,其余都为true

if false or nil then
    print("nil is true")
else
    print("nil is false")
end

if 0 then
    print("0 is true")
else
    print("0 is false")
end

  1. 数据类型number

lua中,只有一种数字类型-number

8字节、双精度

print("测试number")
a=10
print(type(a))
  1. 数据类型String

用单引号或双引号

print('单引号字符串')
print("双引号字符串")

[[]]可以包含换行的字符串

i=[[
我是中国人
我是亚洲人
我是地球人
我是太阳系人
]]
print(i)

字符串与数字做数学运算时,优先将字符串转换成数字

print("测试字符串+")
print("1"+1)
print("1"+"1")

如果字符串不能转成数字将报错

print("测试字符串+")
print("1"+1)
print("1"+"1")
print("x"+1)

如果实现java中字符串连接,使用 .. 符号

print("测试字符串..")
print("1"..1)
print("1".."1")
print("x"..1)

计算字符串长度

print(#"aa")
  1. 数据类型-table

table 可做数组和map

数组下标从1开始。

print("测试table")
tab1={}
tab2={"v1","v2","v3"}
tab3={key1="value1",key2="value2",key3="value3"}

print("-----打印tab3-----")
for k,v in pairs(tab3) do
    print(k.."="..v)  
end

print("-----打印tab2------")
for k,v in pairs(tab2) do
    print(k.."="..v)  
end

print("-----按数组索引打印数组------")
print(tab2[1])
print(tab2[2])
print(tab2[3])

print("-----nil相当于删除------")
tab3["key1"] = nil
for k,v in pairs(tab3) do
    print(k.."="..v)  
end
  1. 数据类型-function

斐波拉系数列:

function fib(n)
    if n == 1 or n == 2 then
        return 1
    else
        return fib(n-1)+fib(n-2)
    end
end

print("fib(10) = " ..fib(10))

匿名函数:

print("----测试匿名函数----")
function ff(tab,func)
    for k,v in pairs(tab) do
        print(func(k,v))
    end
end

tab1={key1="v1",key2="v2"}
ff(tab1,
    function(k,v)
        return k.."="..v
    end
)

  1. 数据类型-其他

  1. thread:协程

  1. userdata:存储c、c++数据类型。

四、变量

  1. 变量

lua变量分为全局变量,局部变量

全局变量:默认,全局有效。

局部变量:从作用范围开始到作用范围结束。需加local 修饰。

a=1

function ff()
    local b=1 
end

print(a)
print(b)


  1. 变量的赋值

function ff2()
    return 2,3
end

a=1
b=2
-- 交换
a,b = b,a
print(a,b)
-- 变量个数<值的个数,忽略多余的值
a,b,c = 1,2,3,4
print(a,b,c)
-- 变量个数>值的个数,不足nil
a,b,c,d = 1,2,3
print(a,b,c,d)

-- 多返回值的函数
a,b = ff2()
print(a,b)
  1. 索引

对table中的元素进行访问

tab = {k1="v1",k2="v2",k3="v3"}
print(tab["k1"])
print(tab.k1)

五、循环

  1. while(循环条件)

do

执行体;

对循环条件的控制;

end

a=1
while(a<=5)
do
    print(a)
    a=a+1
end
  1. for

  1. 数值for

for var=expr1,expr2,expr3(var 从expr1到expr2,expr3 为步长,可为空,默认为1)

do

循环体

end

-- 打印10以内的奇数
for a=1,10,2
do
    print(a)
end
  1. 泛型for

arr={"one","two","three"}
-- 只打印索引
for k in pairs(arr)
do
    print(k)
end
-- 打印索引和值
for k,v in pairs(arr)
do
    print(k,v)
end
  1. repeat util

repeat

循环体

until(条件)

先执行循环体,直到满足条件;

a=1
repeat
    print(a)
    a=a+1
until(a>10)

六、流程控制

if (成立) then

执行体1

else

执行体2

end

七、函数

  1. 函数定义

范围:默认local

格式:

function 函数名(参数列表)

函数体;

return 返回值

end

-- 最大值函数:
function max(arg1,arg2)
    local result = arg1
    if (arg1 < arg2)then
        result = arg2 
    end
    return result
end

print(max(1,2))
  1. 多返回值函数


function findMax(arr)
    local index=1;
    local value=arr[index];
    for k,v in pairs(arr)
    do
        if (v > value)then
            index = k
            value = v
        end
    end
    return index,value
end

index,value = findMax({1,3,5,7,9})
print("最大值索引:"..index.."最大值:"..value)
  1. 可变参数

  1. 可变参数:arg = {...}

function sum(...)
    local arg = {...}
    local result=0;
    for k,v in pairs(arg)
    do
        result = result + v
    end
    return result
end

print("和为:"..sum(1,2,3,4,5))
  1. 获取可变参数的个数: #arg

function Avg(...)
    local arg = {...}
    local result=0;
    local count = #arg;
    for k,v in pairs(arg)
    do
        result = result + v
    end
    return result/count
end

print("avg为:"..Avg(1,2,3,4,5,6))
  1. 函数参数列表中,存在固定参数和可变参数,固定参数全部写在前面


function fmtPrint(fmt,...)
    io.write(string.format(fmt,...))
end

fmtPrint("%s\n","helloworld")
fmtPrint("%d+%d = %d\n",1,1,2)
  1. 选取可变参数的值:select

function ff4(...)
    a,b,c = select(3,...)
    return a,b,c
end

print(ff4(1,2,3,4,5,6,7,8,9))

八、运算符

  1. 算术运算符

+ 加 - 减 * 乘 / 除 % 取余 ^ 乘幂 - 负号 = 等号

  1. 关系运算符

== 等于

~= 不等于

>大于

>= 大于等于

<小于

<= 小于等于

  1. 逻辑运算符

与:and

或:or

非:not

九、数组

  1. 一维数组:

选择排序:

function sort(arr,n)
    for i=1,n-1,1
    do
        local k = i
        for j=i+1,n,1
        do
            if (arr[j] < arr[k]) then
                k = j
            end
        end
        if (k ~= i) then
            local tmp = arr[i]
            arr[i] = arr[k]
            arr[k] = tmp
        end
    end
    return arr
end 

arr = sort({4,3,2,1},4)
for i in pairs(arr)
do
    print(arr[i].." ")
end
  1. 多维数组

function ff4()
    arr={}
    for i=1,3,1
    do
        arr[i]={}
        for j=1,2,1
        do 
            arr[i][j]=i*j
        end
    end
    return arr
end


print("---------------------")

arr = ff4()

for i=1,3,1
do
    for j=1,2,1
    do 
        print(arr[i][j])
    end
end

十、迭代器

  1. for 迭代器

  1. pairs:会遍历所有key,value

  1. ipairs:将跳过不是数字作为key的索引。

  1. for 变量列表 in 迭代函数,状态常量,控制变量

do

循环体

end

1-9的平方:

print("-------迭代器的定义例子--------") -- 求平方 1-9的平方 
function square(iteratorMaxCount,currentNumber)
    if currentNumber < iteratorMaxCount then
        currentNumber = currentNumber +1
        -- if(currentNumber == 2) then                        
        --    return nil,1               
        --  end
    return currentNumber,currentNumber*currentNumber
    end 
end

for i,n in square,9,0
do
    print(i,n) 
end

十一、Table

table 可做数组、可做键值对

table 赋值时,新的table与旧的tabe共用一块内存。

tab={}
tab[1]="1"
print(tab[1])
tab = nil

print("-------------------")
tab={}
-- 类型为table
print(type(tab))
tab[1]="1号元素"
tab["a"]="a号元素"

print("tab a[1] = "..tab[1])
print("tab a[a] = "..tab["a"])

--赋值,newtab 与tab 共用一块内存。
newtab = tab
print("newtab a[1] = "..newtab[1])
print("newtab a[a] = "..newtab["a"])

-- newtab 发生修改,tab 也会修改
newtab["a"]="aa"
print("newtab a[a] = "..newtab["a"])
print("tab a[a] = "..tab["a"])

-- tab 为空,只是tab 变量为空,其指向的内存还由newtab指着,所以这块内存不会回收
tab=nil
print("newtab a[1] = "..newtab[1])
print("newtab a[a] = "..newtab["a"])

十二、模块

  1. 模块

模块中的局部成员不能被外部访问

module.lua

module={}

module.A ="module 中的A"

function module.func1()
    print("module func1")
end

-- 局部函数
local function func2()
    print("module func2")
end

function module.func3()
    func2()
end

return module

调用:test.lua, module.lua

-- 相对路径
require("module")

print(module.A)
print(module.func1())
print(module.func3())

修改LUA_PATH=path/?.lua,可以让lua去其他地方寻找模块。

  1. C包: 直接调用C库中的函数

print.c

#include <stdio.h>

void print()
{
    printf("hello world\n");
}
//gcc -o libprint.so -fPIC -shared print.c 

或者C++编写的库

print.cc

#include <iostream>

//外部接口处理成C格式
extern "C"
{
    void print();
}

void print()
{
    std::cout << "hello world\n";
}

//g++ -o libprint.so -fPIC -shared print.cc

test.lua

local path = "./libprint.so"
local f = package.loadlib(path, "print")
f()

十三、元表

允许我们改变 table 的行为,每个行为关联了对应的元方法

  1. 设置元表、获取元表

tab0 = {}
tab = setmetatable({}, tab0)
tab2 = getmetatable(tab)

-- tab0 与tab2 相同
print(tab0)
print(tab2)
  1. __index 元方法

  1. __index 包含table:在table未查找到键时,获取查找元表的__index键,如果找到且__index中包含一个table,则lua会在表格中查找相应的键。

tab1 = { key2 = "value2" }
tab2 = setmetatable({ key1 = "value1" }, { __index = tab1 })
print(tab2.key1)
print(tab2.key2)

  1. __index 包含函数:在table未查找到键时,获取查找元表的__index键,如果找到且__index中包含一个函数,则lua会将键值传入函数。

mytable = setmetatable({ key1 = "value1" }, {
    __index = function(mytable, key)
        if key == "key2" then
            return "metatablevalue"
        else
            return nil
        end
    end
})
print(mytable.key1, mytable.key2)

__index元方法总结:

1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。
  1. __newindex 元方法

  1. __newindex 包含table:如果对table进行赋值时,覆盖table中不存在键且table有元表,则查找__newindex元方法,如果找到且__newindex为一个table,则在这个table中赋值。

tab0 = {}
tab = setmetatable({ key1 = "value1" }, { __newindex = tab0 })

print(tab.key1)
-- print(tab0.key2)

tab.key1 = "v1"
tab.key2 = "v2"
print(tab.key1)
print(tab0.key2)

  1. __newindex 包含方法:如果对table进行赋值时,覆盖table中不存在键且table有元表,则查找__newindex元方法,如果找到则调用这个方法。

mytable = setmetatable({ key1 = "value1" }, {
    __newindex = function(mytable, key, value)
        rawset(mytable, key, "\"" .. value .. "\"")
    end
})

mytable.key1 = "new value"
mytable.key2 = 4

print(mytable.key1, mytable.key2)
  1. 为表添加操作符

实现两个数组相加:


function table_maxn(t)
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end

mytable = setmetatable({ 1, 2, 3 }, {
    __add = function(mytable, newtable)
        for i = 1, table_maxn(newtable) do
            table.insert(mytable, table_maxn(mytable) + 1, newtable[i])
        end
        return mytable
    end
})



secondtable = { 4, 5, 6 }

mytable = mytable + secondtable
for k, v in ipairs(mytable) do
    print(k, v)
end

其他可实现的表操作符:

  1. __call元方法:将table自身变成一个方法

两个table元素求和:

tab = setmetatable({ 1, 2, 3 }, {
    __call = function(tab, newtable)
        local sum = 0
        for i in pairs(tab)
        do
            sum = sum + tab[i]
        end

        for i in pairs(newtable)
        do
            sum = sum + newtable[i]
        end
        return sum
    end
})

newtable = { 4, 5, 6 }
print(tab(newtable))
  1. __tostring 元方法:使得print不再是地址

返回table的元素和的字符串:

tab = setmetatable({ 1, 2, 3 }, {
    __tostring = function(tab)
        sum = 0
        for i in pairs(tab)
        do
            sum = sum + tab[i]
        end
        return "table的和是: " .. sum
    end
})

print(tab)

十四、lua协程

  1. 相关概念:

lua协程:拥有独立的堆栈、局部变量、pc,同时与其他协程共用全局变量和其他大部分东西。

lua协程与线程的区别:一个具有多线程的程序可以同时运行多个线程,而协同程序需要彼此协作运行,同一时刻只有一个协程运行,运行的协程只有被明确要求挂起时才会挂起。协同程序与同步的线程比较类似,多个线程等待同一个线程锁。

  1. 相关方法

coroutine.create():创建一个协程

coroutine.resume():重启一个协程

coroutine.yield():挂起一个协程

coroutine.status():返回协程的状态,死亡dead,暂停suspended,运行中running

coroutine.running():一个协程对应一个线程,返回running协程的线程号,以及是否为主线程。

  1. 死亡的协程不能再运行

co = coroutine.create(
    function(i)
        print(i)
    end
)

coroutine.resume(co, 1) -- 1
print(coroutine.status(co))  --dead
print(coroutine.resume(co, 2)) -- false   cannot resume dead coroutine
  1. 协程主动退出,暂停的协程可以继续运行

co = coroutine.create(
    function()
        for i = 1, 10, 1
        do
            print(i)
            print(coroutine.status(co))
            print(coroutine.running())
            coroutine.yield()
        end
    end
)

coroutine.resume(co)
print(coroutine.status(co))
print("------------------")
coroutine.resume(co)
print(coroutine.status(co))
print("------------------")
coroutine.resume(co)
print(coroutine.status(co))
  1. yield与resume的交互

co = coroutine.create(
    function(a)
        a = a + 1
        print("第一次协同程序执行输出", a)
        -- b将等于再次启动协程时,resume传入的参数
        local b = coroutine.yield(a)
        print("第二次协同程序执行输出", b)
        return a
    end
)

print(coroutine.resume(co, 1))
print(coroutine.resume(co, 20))
  1. 生产者与消费者(利用:lua协程天然的同步特点)

-- 生产者协程
function produce()
    i = 0
    while (true)
    do
        i = i + 1
        coroutine.yield(i)
    end
end

-- 消费者协程
function consume()
    while (true)
    do
        local status, value = coroutine.resume(co1)
        print(value)
        -- sleep 1 s
        os.execute("sleep 1")
    end
end

co1 = coroutine.create(produce)
co2 = coroutine.create(consume)

-- 主协程等待
coroutine.resume(co2)

十五、Lua错误处理

  1. 语法错误

  1. 运行错误

function add(a, b)
    return a + b
end

print(add(1))

  1. 错误处理

  1. assert(关系表达式,错误信息):assert首先检查第一个参数,若没问题,assert不做任何事情;否则,assert以第二个参数作为错误信息抛出。

function add(a, b)
    assert(type(a) == "number", "a is not number")
    assert(type(b) == "number", "a is not number")
    return a + b
end

print(add(1))
  1. error函数:终止正在执行的函数,并返回message的内容作为错误信息(error函数永远都不会返回)

function add(a, b)
    if (type(a) ~= "number") then
        error("a is not number")
    end
    if (type(b) ~= "number") then
        error("b is not number")
    end
    return a + b
end

print(add(1, 1))
  1. pcall:pcall接收一个函数和要传递给后者的参数,并执行,执行结果:有错误、无错误;返回值true或者或false, errorinfo。

function ff(i)
    error("err")
    print(i)
end

print(pcall(ff, 1))

  1. xpcall:

xpcall接收第二个参数——一个错误处理函数,当错误发生时,Lua会在调用桟展开(unwind)前调用错误处理函数,于是就可以在这个函数中使用debug库来获取关于错误的额外信息了。

debug库提供了两个通用的错误处理函数:

  • debug.debug:提供一个Lua提示符,让用户来检查错误的原因

  • debug.traceback:根据调用桟来构建一个扩展的错误消息

xpcall(function(i)
    print(i)
    error('error..')
end, function() print(debug.traceback()) end, 33)

十六、面向对象

  1. 定义对象

student = {
    name = "zhangsan",
    age = "18",
    gotoSchool = function(name)
        print(name .. "去上学")
    end
}

student.gotoSchool = function(name)
    print(name .. "去上学")
end

function student.gotoSchool(name)
    print(name .. "去上学")
end

student.gotoSchool(student.name)
  1. 构造函数


Student = { name = "default" }

function Student:new()
    s = {}
    setmetatable(s, { __index = self })
    return s
end

s1 = Student:new()
s2 = Student:new()

print(s1.name)
print(s2.name)

s1.name = "zhangsan"
s2.name = "lisi"

print(s1.name)
print(s2.name)

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值