Lua语法入门

基础特性

lua中不需要分号作为语句的结束点

注释语句

-- 单行注释

--[[
 注释语句
]]--

..操作符可以用于拼接类型,拼接后的结果是stringnil不支持拼接)

a = 123 .. 456
-- data type is string
-- data is 123456
print("data type is " .. type(a) .. "\n" .. "data is " .. a)

#代表获取长度,例如可以获取字符串或者数组等的长度。获取的结果是number类型

name = "Jelly"
-- 5
print(#name)

使用#获取长度的规则是:末尾的nil不列入长度计算

a = {1, 2, nil, 3, 4, 5, nil, nil, nil}
-- 6
print(#a)

常用函数

输出语句

print("Hello World")

获取变量类型,将返回变量类型名的string

type()

类型系统

lua中并不需要声明变量类型,它是弱类型的语言

对于空数据而言,它们的类型是nil

a = nil
-- nil
print(type(a))

对于数值而言,它们的类型是number

a = 20.21
-- number
print(type(a))

对于字符串而言,它们的类型是string,不管是单引号或者是双引号

a = 'Hello'
-- string
print(type(a))

对于真假而言,它们的类型是boolean

a = true
-- boolean
print(type(a))

lua中使用没有声明过的变量,不会报错,默认是nil

-- nil
print(magicData)

字符串常见操作

字符串拼接

  • %d:代表与number拼接
  • %a:代表与任意字符拼接
  • %s:代表与string拼接
-- I am No.1
print(string.format("I am No.%d", 1))

其他类型转化为字符串

a = true
b = tostring(a)

其他常用方法

大小写转换,以及倒序字符串

-- HELLO WORLD
print(string.upper("hello world"))
-- hello world
print(string.lower("HELLO WORLD"))
-- OLLEH
print(string.reverse("HELLO"))

查找截取以及修改。lua中字符串从1开始计数,而不是0

-- 查找字符串 a的值为2
a = string.find("Hello", "ell")
-- llo
print(string.sub("Hello", 3, 5))

a = string.gsub("Hello World", "o", "O")
-- HellO WOrld
print(a)

ASCII码互转

-- 将"L"转化为ASCII码
a = string.byte("L")
-- a的值为76 a的类型是number
print(type(a))
-- 将a从ASCII转换为字符串 结果是"L"
print(string.char(a))

运算符

  • lua中没有自增自减运算符,即--++

  • lua中没有符合运算符,即-=+=

  • string类型可以进行运算符操作,会自动转成number,运算的结果也是number

    a = "3.14" + 2
    
  • 由于lua中的数都是number类型,没有整形和浮点型之分,因此

    -- 0.5
    print(1 / 2)
    
  • lua中有幂运算符号

    -- 8.0
    print(2 ^ 3)
    
  • lua中的不等于运算符是~=

    -- true
    print(1 ~= 20)
    
  • 与,或和非的操作符是andornot。短路操作lua中仍然存在

  • lua中不支持位运算符,不支持三目运算符

if语句

a = 20
if a > 10 and a < 30 then
    print("a > 10 and a < 30")
end
a = 100

if a == 20 then
    print("a == 20")
elseif a == 30 then
    print("a == 30")
else
    print("a ~= 20")
    print("a ~= 30")
end

switch语句

lua中没有switch语句

循环语句

while循环

输出01234

num = 0
while num < 5 do
    print(num)
    num = num + 1
end

do-while循环

输出012345

num = 0
repeat
    print(num)
    num = num + 1
until num > 5

for循环

lua中的for循环语句会默认进行+1操作,且循环终止的条件是<=

-- 输出 0 1 2 3 4 5
for i = 0, 5 do
    print(i)
end

以上代码相当于

for (int i = 0; i <= 5; i++)
    std::cout << i << std::endl;

如果不想采用默认的+1操作,可以显式指明

-- 输出 0 2 4
for i = 0, 5, 2 do
    print(i)
end

以上代码相当于

for (int i = 0; i <= 5; i += 2)
    std::cout << i << std::endl;

如果想采用递减操作,也是显式指明的操作

-- 输出 5 4 3 2 1 0
for i = 5, 0, -1 do
    print(i)
end

函数

无参数无返回值

以下代码展示函数的声明和调用,与C++相同,声明和调用的顺序是固定的

function func1()
    print("this is func1")
end

func1()

除此之外还可以有类似“匿名函数”的写法

func2 = function()
    print("this is func2")
end

func2()

带参数函数

同理,lua是弱类型的语言,因此函数参数不需要声明类型

function func1(a)
    print(a)
end

func1(20)

更重要的,如果参数数量不匹配,那么会自动补全或丢弃

function func1(a, b)
    print(b)
end

-- 补全两个nil 输出nil
func1()
-- 丢弃末尾两个参数 输出30
func1(20, 30, 430, 5)

函数返回值

由于是弱类型语言,因此不需要指明返回值类型

function cal(a, b)
    return a * b
end

print(cal(2, 3))

多返回值的处理情况

function cal(a, b)
    return a + b, a - b, a * b
end

data1, data2, data3 = cal(2, 3)

print(string.format("%d %d %d", data1, data2, data3))

多返回值的情况可以参照C++17中的结构化绑定。同样的多余的返回参数如果没有变量接住,那么也会被丢弃;如果声明了多个变量但返回的元素个数不够,那么会默认置空

template<typename T>
std::tuple<T, T, T> cal(T a, T b) {
    return {a + b, a - b, a * b};
}

int main() {
    auto [data1, data2, data3] = cal(2, 3);
    std::cout << data1 << " " << data2 << " " << data3 << std::endl;
}

函数的隐藏

由于Lua中不存在函数重载,因此函数将会出现重定义的情况(即隐藏先声明的函数)

function func(a)
    print(a)
end

function func()
    print("empty func")
end

-- 参数100被丢弃 然后输出empty func
func(100)

变长参数

function func(...)
    table = {...}
    for i = 1, #table, 1 do
        print(table[i])
    end
end

func(100, 200, "Hello", true, 3.14)

换做C++的写法那就是

template<typename... Ts>
void func(Ts... args) {
    ((std::cout << args << std::endl), ...);
}

int main() {
    func(100, 200, "Hello", true, 3.14);
}

函数嵌套

形成一个闭包,变量x的生命周期延长

function func(x)
    return function(y)
        return x + y
    end
end

funcObj = func(5)
-- 输出15
print(funcObj(10))

由于C++中需要手动管理对象的生命周期,按引用捕获并不会延长变量的生命周期,所以只能使用按值捕获,因此C++的写法是

auto func(int x) {
    return [=](int y) { return x + y; };
}

int main() {
    // 存在捕获 所以使用auto
    auto funcObj = func(5);
    std::cout << funcObj(10) << std::endl;
}

table是一个数据类型,不论是数组,字典或者是类等等,它们的类型都是table

数组

如下图即声明了一个数组,lua中的数组并不要求数组内元素类型的一致

a = {1, false, 3, "123"}

lua中下表索引是从1开始的,通过[]对数组中元素进行访问。lua中数组越界并不会导致程序崩溃,它会返回nil

-- false
print(a[2])
-- nil
print(a[100])

二维数组

a = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }

for i = 1, #a do
    for j = 1, #a[i] do
        print(a[i][j])
    end
end

自定义索引

lua中可以自定义数组的索引,如下图代码,令索引1的值为1,索引2的值为2,索引3的值为3,索引4的值为4

a = {[1] = 1, [2] = 2, [3] = 3, [4] = 4}

lua中可以跳跃的指定索引,被忽略的索引在访问时值为nil

a = {[1] = 1, [2] = 2, [3] = 3, [6] = 4}
-- nil
print(a[5])

因此在此基础上就可以实现所谓“哈希表”

a = {["name"] = "Jelly", ["age"] = 20, ["sex"] = 0}

-- age     20
-- name    Jelly
-- sex     0
for k, v in pairs(a) do
    print(k, v)
end
-- 直接新增元素
a["score"] = 100
-- 访问新增加的元素
print(a["score"])

ipairs和pairs迭代器遍历

a = {[0] = 0, 1, 2, [-1] = -1, [5] = 5}

-- 使用ipairs迭代器只能访问到数组中的元素1和元素2
-- ipairs遍历将会从1开始往后遍历 且只能访问连续索引的数据 遇到断序后无法继续往后访问
for k, v in ipairs(a) do
    print("key:" .. k .. " value:" .. v)
end

print()

-- 使用pairs迭代器能够访问数组中的所有元素
for k, v in pairs(a) do
    print("key:" .. k .. " value:" .. v)
end

至此我们可以将其理解为是C++中的std::unordered_map,然后通过std::pair去对键值对进行访问

上一篇:c# – 在ControlTemplate的DataTrigger中使用时,TemplatedParent为null


下一篇:《剑指Offer》24-反转链表