Lua语言:从入门到高级

本文详细介绍了Lua语言的基础知识,包括基本输出和注释、数据类型和变量、数学计算、字符串操作、控制结构(if、循环)、用户输入、table的使用、函数定义与特性、co-routines、文件处理、os模块、自定义模块、面向对象模拟以及metamethods运算符重载。
摘要由CSDN通过智能技术生成

目录

参考链接

1. 基本输出和注释

1.1. 基本输出

1.2. 注释

2. 数据类型和变量

2.1. 数据类型

2.2. 变量

3. 数学计算

4. string

4.1. 多行字符串

4.2. string的函数

5. if语句

6. 循环语句

6.1. for loop

6.2. while loop

6.3. do while loop

7. 用户输入

8. table

8.1. table的创建

8.2. table的遍历

8.3. table的函数

8.4. 多维table

9. 函数

9.1. 函数的定义

9.2. 函数的特性

9.3. 递归

9.4. 匿名函数

9.5. 不定长参数

10. co-routines

11. files

12. os module

13. custom modules

14. 面向对象编程

14.1. 定义一个对象

14.2. 创建一个类

14.3. 类的继承

15. metamethods 运算符重载


参考链接

入门学习视频:

【YouTube高赞中英字幕】4个小时 Lua完整教程 从入门到高级_哔哩哔哩_bilibili

环境配置参考:

VSCode 配置 Lua 开发环境(清晰明了)_lua vscode-CSDN博客

1. 基本输出和注释

1.1. 基本输出

-- print输出,自动换行
print("hello world")

-- ','分隔会对输出制表操作
print("dsadasd","dasdasd")

-- '..' 表示拼接
print("dasda" .. "dasd ")

-- 转义字符包括 \n \t \v \\ \"等等
print("hello\nWorld")

1.2. 注释

-- 两个短破折号表示单行注释
--[[
  随后跟两个中括号表示多行注释
  注意第二个破折号和第一个左中括号之间不能有空格
]]

2. 数据类型和变量

2.1. 数据类型

  • nil 表示空值
  • number 表示数字,包括整数和浮点数,如3, 3.14
  • string 字符串,可以用''或""表示,如'hello'"world"
  • boolean 表示布尔变量,包括truefalse
    • 只有falsenil结果为false
    • 其他包括0""的结果都为true
  • table 后面table章节详解

tonumber(string)tostring(number)可以实现numberstring的转化

2.2. 变量

lua的变量弱类型,不需要提前规定类型名,并且变量的类型可以修改

-- local varname 创建局部变量
local var -- 默认为nil

local name = 'jack'
name = 18 -- 变量类型可以修改
-- 创建全局变量
-- 1. 直接用varname创建
-- 2. 用_G.varname创建
-- ps: 通常全局变量首字母大写
C = nil
_G.Str = "hello"
-- 多个变量可以依次命名和定义
local x,y,z = 1, 2, 3

-- type(varname)可以获得变量的类型
print(type(x)) -- number

3. 数学计算

-- 基本运算包括 + - * / % ^

-- 此外还有math库,包括大部分数学运算函数
-- 如max, min, floor, ceil...

-- math包括随机数
math.randomseed(os.time()) -- 随机数种子
math.random() -- 生成[0,1]的随机数
math.random(1,10) -- 生成[1,10]的随机数

4. string

4.1. 多行字符串

-- 用[[]]来包括
-- 会考虑字符前面的占位符
-- ]]
name = [[
hello 
  world
]]

4.2. string的函数

-- #strname 或 string.len(strname)得到长度
print(#str)

-- tostring(number)把number转为string
tostring(22)

-- string.lower(strname) 转小写

-- string.upper(strname) 转大写

-- string.sub(strname, start, end)取子串,参数分别是串名、开始索引和结束索引
print(string.sub(str,2,3))

-- string.char(number)从ASCII码转为字符
print(string.char(65))

-- string.rep(strname,time,分隔符)把字符串重复time次,然后用分隔符进行分隔
print(string.rep(str,10,','))

-- string.format() c风格书写
print(string.format("pi:%.2f\nMy age: %i",math.pi,18))

-- string.find(strname,要查找的字符串),返回在原串的开始索引
print(string.find(str,"el"))

-- string.match(strname,要匹配的字符串)返回能被匹配的子串
print(string.match(str, "el"))

-- string.gsub(strname,匹配字符串,替换字符串),把字符串的匹配字符串换成替换字符串
print(string.gsub(str,'e','wow'))

5. if语句

-- 只有nii和false会得到false,其他都是true
-- lua 中不等于是 ~=
-- 关系运算符包括 and, or, not
-- if语句
-- if 条件 then 执行语句 end
local age = 18 
if age > 17 and age < 60 then
    print("suitable!")
end
-- if-else语句
-- if 条件 then 执行语句
-- elseif 条件 then 执行语句
-- else 执行语句
-- end
if age > 17 then
    print("if statement")
    if type(age) == 'number' then
        print("if in if")
    end
elseif age > 10 then
    print("elseif statement")
else
    print("else statement")
end

6. 循环语句

注意:lua的任何索引都是从1开始

6.1. for loop

for i = 1, 10, 1 do
    print(i)
end

-- 等价于 for (i = 1; i <= 10; ++i)
-- 其中step可以省略,默认为1

-- 可以逆向循环,把step设为负值即可
for i = 10,1,-1 do
    print(i)
end

6.2. while loop

-- while 条件判断 do
-- 执行语句
-- end
while count > 0 do
    print(count)
    count = count - 1
end

6.3. do while loop

-- repeat
-- 执行语句
-- until 终止条件
local t = 1
repeat
    print(t)
    t = t + 1
until t > 10

7. 用户输入

-- io.read()读取用户输入
local res = io.read()
print(res)

-- io.write()执行不换行输出
io.write("hello world")

8. table

8.1. table的创建

-- 用varname = {}来创建table
-- table内可以有多个元素
-- 每个元素的类型可以各不相同
local arr = {10, true, "hello", 2,4}

8.2. table的遍历

-- #获取table的长度
-- [index]对元素进行访问

-- 可以用for遍历table
for i = 1, #arr do
  -- 执行语句
end

-- 键值对的for循环,其中key是索引,value是值,t是table
for key, value in pairs(table) do
  -- 执行语句
end

8.3. table的函数

-- table.sort(table_name) 对table进行排序
local nums = {4322,54,123,7567,0,31,4,56}
table.sort(nums)

-- table.insert(tablename,index,value)
-- 在table的第index的位置插入value
table.insert(nums,2,'lol')

-- table.remove(tablename, index)
-- 删除table的index位置的元素
table.remove(nums,5)

-- table.concat用分隔符连接table
print(table.concat(nums, '?'))

8.4. 多维table

-- 定义多维table
local arrs = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}

-- 使用下标访问
print(arrs[1][1])

-- 遍历多维table
for i=1,#arrs do
    for j = 1, #arrs[i] do
        print(arrs[i][j])
    end
end

9. 函数

9.1. 函数的定义

-- 函数分为局部和全局
-- 局部定义为local,全局就是不加修饰
local function display(var)
    print(var)
end

--函数的另一种定义法,将函数名写在前面
local display = function(var)
    print(var) 
end

9.2. 函数的特性

-- 默认参数:在函数体里面写var = var or defaultval
local function getAge(age)
    age = age or 5 -- 默认参数为5
    print(age)
end
getAge()--默认参数为5

-- 函数体内定义的全局变量作用域外可以访问
local function func(i)
    Y = i -- 全局变量,作用域外可以访问
end
func(7)
print(Y)

-- return 返回参数
local function sum(num1, num2)
    return num1 + num2
end

-- 多值返回与接收
local function twoRet(num1, num2)
   return num1, num2 
end
local n1, n2 = twoRet(9, 0)

9.3. 递归

-- 在函数体内调用自己
local function jiecheng(num)
    if num == 1 then
        return 1
    end

    return num * jiecheng(num - 1)
end

9.4. 匿名函数

local function func()
    return function () -- 返回了一个匿名函数
        return 10
    end
end

local x = func() -- 此时x是函数

9.5. 不定长参数

-- 参数列表传入'...'表示不定长参数
-- 如果要对不定长参数进行遍历,需要添加{...}将其变成table
local function sum(...)
    for key, value in pairs({...}) do --用中括号把可变参数变成table
        print(key,value)
    end
end
sum(2,3,5,7,11)

10. co-routines

协程使多个函数可以以自定义的方式交替执行

-- coroutine.create(function or 匿名函数)
-- 创建协程

-- coroutine.status(coroutine_name)
-- 得到该协程状态
  -- "running" 正在运行
  -- "suspended" 挂起或还没有开始运行
  -- "normal" 是活动的,但没有运行
  -- "dead" 运行完或因错误停止

-- coroutine.yield()
-- 挂起当前协程

-- coroutine.resume(coroutine_name)
-- 继续或开始一个协程 
-- 创建协程1
local routine_1 = coroutine.create(
    function ()
        for i = 1, 10, 1 do
            print("Routine 1: " .. i)
            if i == 5 then
                -- 此时挂起协程1
                coroutine.yield()
            end
        end
    end
)

local routine_func = function ()
    for i = 11, 20, 1 do
        print("Routine 2: " .. i)
    end
end

-- 创建协程2
local routine_2 = coroutine.create(routine_func)

-- 运行协程1
coroutine.resume(routine_1)
print(coroutine.status(routine_1)) -- 此时协程1挂起
coroutine.resume(routine_2) -- 运行协程2

-- 启动协程1
if coroutine.status(routine_1) == 'suspended' then
    coroutine.resume(routine_1)
end
print(coroutine.status(routine_1)) --协程1执行完毕

11. files

-- io.output(filename) 创建文件并选中,如果已存在会清空
-- io.write(内容) 向被选中的文件中写入内容
-- io.close()关闭当前被选中的文件

io.output("myFile.txt")
io.write("hello")
io.close()
-- io.input(filename)读取并选中文件
-- io.read(number)读取前number个字符
-- io.read(var)按照var的方式进行读取
  -- "n" 读取一个数字,根据lua的转换文法返回浮点数或整数
  -- "a" 从当前位置开始读取整个文件
  -- "l" 读取一行并忽略行结束标记
  -- "L" 读取一行并保留行结束标记
-- io.read()是按照指针操控的顺序读

io.input("myFile.txt")
local file = io.read(5)
local num = io.read("l")
io.close()
print(file)
print(num)
-- 可以直接用io.open访问文件,然后选择模式
-- 模式包括读、写、追加等
-- 'a'表示追加,可以在文件末尾追加内容
local file = io.open("myFile","a")

--此时要用file:来控制对文件对象的操作
io.write("hahaha") -- 错误
file:write("hahaha") --正确

--此时关闭文件要用file:close
file:close()

12. os module

-- time: 如果不传参就是1970到现在,否则就是1970到参数的时间
print(os.time({
    year = 2000,
    month = 10,
    day = 20,
    hour = 13,
    min = 20,
    sec = 10
}))

-- os.difftime(两个时间变量) 返回时间差

-- os.date() 返回日期

-- os.rename(文件名, 新名字) 重命名文件

-- os.remove(文件名) 删除文件

-- os.execute(指令字符串) 在终端执行指令

-- os.clock() 计时
local start = os.clock()
-- 执行操作
local ended = os.clock()
print(ended - start)

-- os.exit() 退出程序

13. custom modules

创建.lua文件,然后编写自己的module,随后在主程序代码中用require()函数引入module

-- modules返回的是一个table
-- 把要实现的函数体放在table体内,用tablename.funcname表示
-- 函数必须是全局函数,因为要在其他地方使用

_G.mmath = {}

-- 定义为mmath表的内容
function mmath.add(x, y)
    return x + y
end

function mmath.power(num1, num2)
    return num1 ^ num2
end

return mmath
local mod = require("MyMath")
print(mod.add(1,5))
print(mod.power(2,6))

14. 面向对象编程

lua不是面向对象语言,但是我们可以用table和函数来模拟面向对象

14.1. 定义一个对象

local t = {
    name = "Jack",
    age = 18,
    friend = {"Fred"}
}

print(t.name) -- 访问对象的属性

14.2. 创建一个类

-- 写成一个返回table的函数
-- 其中类名就是函数名
-- 返回匿名table
-- 返回值前面可以定义默认参数
-- self可以访问table的元素
local function Pet(name)
    name = name or "Luis" --默认参数
    return {
        name = name, -- 定义属性
        status = "hungry",

        feed = function(self) -- 定义成员函数
            self.status = "full"
        end
    }
end

local cat = Pet("Kitty")
print(cat.status) --用dot 访问变量
cat:feed() -- 用:访问函数

关于使用冒号和点号的区别,可以参考理解Lua中点号和冒号的区别及适用场合_lua冒号换成点-CSDN博客

14.3. 类的继承

-- 定义函数续写table
-- 函数名即为派生类的名字
-- 最后返回值依然是table
local function Dog(name, breed)
    local dog = Pet(name) -- 获得table

    dog.breed = breed -- 续写table的属性
    dog.loyalty = 0

    dog.isLoyal = function (self) --定义函数
        return self.loyalty >= 10
    end

    dog.bark = function (self)
        print("Woof Woof")
    end

    --重写函数
    dog.feed = function (self)
        self.status = "full"
        self.loyalty = self.loyalty + 10        
    end

    return dog
end

local lassy = Dog("Lassy", "Poodle")
lassy:feed()

if lassy:isLoyal() then
    print("good dog")
else
    print("bad dog")
end

15. metamethods 运算符重载

-- 定义一个table叫metatable,然后在里面对运算符进行重写
  -- 左边是运算符的表示,右边是函数体,可以是正常函数,也可以是匿名函数
  --运算符表示如下:
  --[[
      __add = +
      __sub = -
      __mul = *
      __div = /
      __mod = %
      __pow = ^
      __concat = ..
      __len = #
      __eq = ==
      __lt = <
      __le = <=
      __gt = >
      __ge = >=\
      ......
  ]] 
-- 然后使用setmetatable(要重载的table,metatable)函数来进行重载

local metatable = { -- 定义如何重写
    __add = function (x,y) -- 用匿名函数定义重写形式
        return x.num + y.num
    end,
    __sub = function (x,y)
        return x.num - y.num        
    end
}

local tbl1 = {num = 50}
local tbl2 = {num = 40}

setmetatable(tbl1, metatable) -- 绑定tbl1进行重写

print(tbl1 + tbl2)
print(tbl1 - tbl2)
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值