Lua入门

base

-- 定义一个结算阶乘的函数
function fact(n)
    if n == 0 then
        return 1
    elseif n < 0 then
        return 0
    else
        return n * fact(n - 1)
    end
end

print("enter a number:")
a = io.read("*n")
print(fact(a))

-- 多行注釋有點怪説是
--[[
字母数字下划线组成的字符串,_VERSION 下划线跟大写是特殊用途,一般不要这样写
保留字:and break do else elseif end false goto for function if in local nil not or repeat return then true until while
大小写敏感
]]

-- 奇怪但有用的注释方法
---[[
function test()
    print(1000)
end
--]]


-- ; 的用途
a = 5 
b = 5

a = 5; b = 5

a = 5 b = 5

-- and or短路求值
-- (a > b) and a or b -- 类似a > b ? a : b

-- == 是严格判等, 5 == true -> false

print(arg[-1],arg[0], arg[1], arg[2]) -- 输出命令行参数

number

print("整形浮点型的类型都是number:")
print(string.format("type(1) = %s", type(1)))
print(string.format("type(1.0) = %s", type(1.0)))
print(string.format("type(1e3) = %s", type(1e3)))

print("特殊情况需要判断具体类型时:")
print(string.format("math.type(1) = %s", math.type(1)))
print(string.format("math.type(1.0) = %s", math.type(1.0)))
print(string.format("math.type(1e3) = %s", math.type(1e3)))

print("测试string.format:")
print(string.format("整数:%d, 浮点数:%.2f, 字符串:%s", 10, 3.14159, "hello"))

-- 不等于 ~=
-- 内置数学库 math
math.deg(math.pi / 2) -- 弧度转角度
math.rad(90) -- 角度转弧度
math.random(1, 10)

--[[ % lua比较特殊,x/k让余数始终落在[0, k-1]区间
> for i = -10, 10 do
>> print(i, i %3)
>> end
-10     2
-9      0
-8      1
-7      2
-6      0
-5      1
-4      2
-3      0
-2      1
-1      2
0       0
1       1
2       2
3       0
4       1
5       2
6       0
7       1
8       2
9       0
10      1
--]]

-- // floor 向负无穷取整
math.floor(3.14)  -- 输出:3
math.floor(-3.14) -- 输出:-4

-- 环绕溢出
print(string.format("math.maxinteger + 1 = %d", math.maxinteger + 1))  -- 输出:math.mininteger
print(string.format("math.maxinteger * 2 = %d", math.maxinteger * 2))  -- 输出:-2
print(string.format("math.mininteger * 2 = %d", math.mininteger * 2))  -- 输出:

-- 推导
print(string.format("math.maxinteger = %d", math.maxinteger))
-- max + 1 = min
print(string.format("math.maxinteger + 1 (%d) = math.mininteger (%d)", math.maxinteger + 1, math.mininteger))
-- min - 1 = max
print(string.format("math.mininteger - 1 (%d) = math.maxinteger (%d)", math.mininteger - 1, math.maxinteger))
-- max * 2 = max + 1 + max - 1 = min + max - 1 = -1 -1 = 输出:-2
-- min * 2 = (max + 1) + (max + 1) = max * 2 + 2 = -2 + 2 = 输出:0
--[[
关于 max 和 min的环绕溢出推导
max + 1 = min
min - 1 = max

max * 2 = max+1 + max-1 = min + max -1  = -2
min * 2 = max + 1 + max + 1 = -2 + 2 = 0

max * 4 = max * 2 + max * 2 = -4
min * 4 = min * 2 + min * 2 = 0 + 0 = 0
max * max = max * (max - 1) + max = - (max - 1) + max = 1
min * min = min * 2 * (min // 2) = 0 * 0 = 0
--]]

-- ^右结合性
print(string.format("2 ^ 3 ^ 4 = %d", 2 ^ 3 ^ 4)) 
print(string.format("2 ^ -3 ^ 4 = %d", 2 ^ (-3 ^ 4)))

table

-- lua中Table的用法类似其他语言中的字典
-- 比较特别的是Key可以是任意类型

--[[
可以当作结构体或者字典来使用
a = {}
a['name'] = 'zhangsan'
a.name = 'lisi'
那看起来结构体的用法更好了,可以少敲字符
--]]

-- 作为key时,浮点型如果会被转换为整形

--[[
特殊的构造方式
a = {2, 3, 4} <--> a = {[1]=2, [2]=3, [3]=4}
]]

-- lua中索引从1开始

-- 如果想要表示数组或者列表,用递增的整型作为索引即可
-- 长度操作符#返回数组中不为nil的元素个数,所以对于有空洞的数组/字典是不可靠的,从索引1开始连续递增查找知道遇到nil的索引
-- a = {[1] = 10, [100] = 1}, #a  -- 结果是1

--[[
关于遍历Table
1. 通过索引下标遍历(由于#操作符存在nil问题,所以很有可能漏掉元素),顺序是确定的,适合遍历数组
for i = 1, #a do
    handle_item(a[i])
end
2. pairs()函数遍历所有键值对,顺序是不确定的,适合遍历字典
for k, v in pairs(a) do
    handle_item(k, v)
end
3. ipairs()函数遍历数组部分(从1开始的连续整数索引),顺序是确定的,适合遍历数组
for i, v in ipairs(a) do
    handle_item(i, v)
end
]]

--[[
关于安全访问
如果想要访问a.b.c这种多级嵌套的table,必须确保每一级都不为nil,否则会报错
val = a and a.b and a.b.c -- 这种写法比较繁琐,要访问多级嵌套就更麻烦
val = (((a or {}).b) or {}).c  -- 算是一种简化的写法,能减少访问次数
]]

-- 表标准库
a = {}
table.insert(a, 1)  -- 在数组末尾添加元素
table.insert(a, 2, 100)  -- 在索引2处插入元素100
table.remove(a) -- 删除数组末尾元素
table.remove(a, 2) -- 删除索引2处的元素,后续元素前移
table.move() 

string

-- #长度操作符
str = 'hello'
print(#str)  -- 输出 5

-- ..连接操作符号
str1 = str .. ' world'
print(str1)  -- 输出 hello world
print(math.type(str1))  -- 输出 nil,math.type 只能识别数字,其他的都会返回nil

-- 字符串常量,单双引号都可以,内部的不同引号无需转义
str2 = "hello"
str3 = 'hello'
str4 = "hello 'world'"
str5 = '"hello" world'
print(str2, str3, str4, str5)

-- 长字符串,多行字符串
long_str = [[this is a long string in lua]]
long_str2 = [[
-- multiline start
this is a multi line long string in lua
it can be multiline
contains multi lines
-- multiline end
]]
print(long_str)
print('\n' .. long_str2 .. '\n')

-- 由于字符串不是整形,任何有字符串参与的算数操作 最终都会被当作 float 处理
print("3" + 1)      -- 输出 4.0

-- tonumber & tostring
print(tonumber("3") + 1)  -- 输出 4
print(tostring(3) .. "1")  -- 输出 31

--[[
字符串标准库
string.len, string.lower, string.upper, string.sub, string.rep, string.reverse, string.match可以匹配字符串, string.gsub字串替换
--]] 

-- 和python一样,lua中字符串是不可变的
-- string.format是重要的字符串格式化函数 %d-十进制数,%f-浮点数,%s-字符串,%x-十六进制数
print(string.format("%02d/%02d/%04d", 9, 11, 2025))  -- 输出 09/11/2025
a = "this is a test string"
print(string.gsub(a, 't', '**'))

function

-- 函数与其他语言中函数没有特别的不同

--[[
1. 调用函数传入的参数可以不足,缺少的参数会被补nil
2. 支持多返回值,函数调用将尽可能多返回值来匹配待赋值的变量,函数返回值不够的情况下会补nil
2.special 仅当函数调用是表达式列表中的最后一个时才返回多个值,否则只会返回第一个
3. 多返回值个数在不同的逻辑分支中是可变的
4. 支持可变长参数列表...
4.1 通过table.pack(...)或者select('#', ...)来获取具体的可变参数,两者都不会把nil忽略
4.2 table.unpack()可以把table中的元素展开成参数列表
]]

function foo(a, b, c)
    print(a, b, c)
    return 1, 2
end
print(foo(1))  -- 输出 1 nil nil

a, b, c = foo(1, 2, 3)  -- a = 1
print(a, b, c)

function test_dynamic_return(i)
    if i == 1 then
        return 1, 2, 3
    else
        return 4, 5
    end
end
print(test_dynamic_return(1))  -- 输出 1 2 3
print(test_dynamic_return(2))  -- 输出 4 5 

-- 可变长参数
function foo_dynamic_param_num(...)
    local args = table.pack(...)
    print('table.pack打印:')
    for i = 1, args.n do
        print(args[i])
    end

    print('select打印:')
    local args_num = select('#', ...)
    if args_num == 0 then
        return
    end
    for i = 1, args_num do
        print(select(i, ...))
    end
end

foo_dynamic_param_num(1, 2, 3, nil, 5)

-- 局部变量
--[[
1. lua中默认都是全局变量,除非显式声明为local局部变量,类似于c++局部变量,存在作用域
2. 可以先声明不显式赋值,默认会被赋为nil
3. 特殊的用法 local foo = foo, 相当于赋值
4. 对于table和函数,赋值是复制引用,变量指向同一个对象。
4.special 但是对于基本类型(number, string, boolean),赋值是复制值
]]

base_type_var = 100
table_var = {1, 2, 3}
function test_local_var()
    do
        local base_type_var = base_type_var -- 局部变量,值赋值
        base_type_var = 200
        print('local var' .. base_type_var)

        local table_var = table_var  -- 局部变量,引用赋值
        table_var[1] = 1000
        for i = 1, #table_var do
            print(string.format('local table %d = %d', i, table_var[i]))
        end
    end
    print('static var' .. base_type_var)  -- 全局变量
    for i, v in ipairs(table_var) do
        print(string.format('local table %d = %d', i, v))  -- 全局变量
    end
end

test_local_var()

-- 控制结构
--[[
1. if while repeat for 都得显式的加上终结符end
2. lua中没有switch语句,可以用if elseif elseif...end来实现类似功能
3. repeat...until类似于do...while,重复执行循环体直到条件为真
4. for循环有两种形式,数值型和泛型,数值型就是指定开始和结束索引及步长,泛型就是table.pack, pairs和ipairs迭代器
5. goto语句没事儿还是别用了,有点另类
]]


print('repeat...until:')
i = 3
repeat
    print(i)
    i = i - 1
until i <= 0

print('数值型for:')
for i = 1, 5, 2 do -- 第三个参数为步长
    print(i)
end

print('泛型for:')
a = {1, 2, 3, x=4}
for i, v in ipairs(a) do
    print(i, v)
end
for i, v in pairs(a) do
    print(i, v)
end

function test_goto()
    local i = 1
    if true == true then
        goto pin_1
    end
    ::pin_1:: do
        print('test_goto:', i)
    end
end
test_goto()

function test_elseif()
    local i = 0
    if i <= 1 then
        print('i <= 1')
    elseif i <= 2 then
        print('i <= 2')
    else
        print('i is other value')
    end
end
test_elseif()
posted @ 2025-09-27 20:22  yocichen  阅读(7)  评论(0)    收藏  举报