Lua基础知识

本文介绍了在Linux和Mac系统上安装Lua5.3.0的过程,涵盖了Lua的基本语法、数据类型(如表、元表、函数、thread、userdata等)、字符串操作、模块与包管理、迭代器、垃圾回收以及面向对象编程的概念。
摘要由CSDN通过智能技术生成

Linux 系统上安装

Linux & Mac上安装 Lua 安装非常简单,只需要下载源码包并在终端解压编译即可,本文使用了5.3.0版本进行安装:

curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install

编写一个简单的main.lua文件(脚本式编程)

print("hello huahua")

执行 lua main. lua 输出hello huahua

Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

基本语法

lua提供交互式编程模式。通过lua -i或者lua启用

全局变量,局部变量

默认情况下变量总是认为是全局的。全局变量不需要声明。访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。如果你想删除一个全局变量,只需要将变量赋值为nil。

a = 5               -- 全局变量
local b = 5         -- 局部变量

function joke()
    c = 5           -- 全局变量
    local d = 6     -- 局部变量
end

数据类型

Lua 中有 8 个基本类型分别为:nil、boolean,number(表示双精度类型的实浮点数)、string、userdata(表示任意存储在变量中的C数据结构)、function(由 C 或 Lua 编写的函数)、thread(表示执行的独立线路,用于执行协同程序) 和 table。

1.nil(空)

nil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值:

对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉

Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true:

print(type((10.4 * 3)))

print(type(a))
a = 10
print(a)
a = nil
print(a)

输出: 

2.table

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。

x = {}
x["k"] = "val"
k = 10
x[k] = 22

x[k] = x[k] + 10

for q , p in pairs(x) do
        print(q .. "-" .. p )
end

输出 10 - 32

2.元表(metetable)

函数

  • setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
  • getmetatable(table): 返回对象的元表(metatable)。

3.function(函数)

在 Lua 中,函数是被看作是"第一类值(First-Class Value)",函数可以存在变量里:

function 可以以匿名函数(anonymous function)的方式通过参数传递:

function testFun(tab,fun)
        for k ,v in pairs(tab) do
                print(fun(k,v));
        end
end


tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val)--匿名函数
        return key.."="..val;
end
);

4.thread(线程)

在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

5.userdata(自定义类型)

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

6.字符串

字符串或串(String)是由数字、字母、下划线组成的一串字符。

在 Lua 中,字符串是一种基本的数据类型,用于存储文本数据。

Lua 中的字符串可以包含任意字符,包括字母、数字、符号、空格以及其他特殊字符。

Lua 语言中字符串可以使用以下三种方式来表示:单引号,双引号,[[" "]]

方法

string.upper(str)---字符串全部转为大写字母。


string.upper(str)----字符串全部转为小写字母。


string.gsub(main str, find string, replace string,num)----在字符串中替换。mainString 为要操作的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数


string.find(std,substr,[init,[plain]])---------在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。

init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。

plain 表示是否使用简单模式,默认为 false,true 只做简单的查找子串的操作,false 表示使用使用正则模式匹配。


string.reverse(arg)--字符串反转


string.format(...)---返回一个类似printf的格式化字符串


sting.len(str)----计算字符串长度。


string.rep(string,n)--

if语句

if 条件表达式 then
语句块
elseif 条件表达式 then
语句块
else
语句块
end

循环语句

while

while语句:
while 条件表达式 do
语句块
end

for循环语句

for语句:
for 变量=初值,终值,步长(或省) do
语句块
end

for 变量1,变量2,…,变量n in 迭代器
do
语句块
end

逻辑运算符

下表列出了 Lua 语言中的常用逻辑运算符,设定 A 的值为 true,B 的值为 false:

操作符描述实例
and逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。(A and B) 为 false。
or逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。(A or B) 为 true。
not逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。

Lua 迭代器

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。

在 Lua 中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。

lua模块与包

模块

模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。

上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.

-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module

require函数

require函数用来加载模块。

require ("<模块名>")

1.执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。

require("moudle")

moule.func3()---可以直接调用

2.或者给加载的模块定义一个变量名,方便调用

require ("module")

print(module.constant)
module.func3()

Lua在一个叫loadlib的函数内提供了所有的动态连接的功能。这个函数有两个参数:库的绝对路径和初始化函数。

local path = "/usr/local/lua/lib/libluasocket.so"
local f = loadlib(path, "luaopen_socket")

loadlib 函数加载指定的库并且连接到 Lua,然而它并不打开库(也就是说没有调用初始化函数),反之他返回初始化函数作为 Lua 的一个函数,这样我们就可以直接在Lua中调用他。

Lua协同程序

Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。

协同程序可以理解为一种特殊的线程,可以暂停和恢复其执行,从而允许非抢占式的多任务处理。

协同是非常强大的功能,但是用起来也很复杂。

协同程序由coroutine模块提供支持

coroutine模块中的方法

corourine.create(func)---创建corourine;创建一个线程,返回一个线程实例

corourine.resume(co,...)---启动一个线程,并将参数传给调用的函数

corourine.yield(...)----挂起corourine;将当前线程挂起,并将参数返回;

corourine.status()---查看corourine状态(三种状态:dead,suspended,running,normal(一个协程在运行时调用其他协程))

corourine.wrap(func)---创建一个协程,但是返回的是一个函数;

corourine.running()---返回以恶搞正在运行的corourine,返回一个corourine的线程号

resume和yield的配合强大之处在于,resume处于主程中,它将外部状态(数据)传入到协同程序内部;而yield则将内部的状态(数据)返回到主程中。


function foo(a)
	print("foo :", a) 
	return coroutine.yield(2 * a) 
end

co = coroutine.create(function(a, b, c)
	print("first resume :", a ,b ,c)
	local x = foo(c + a)

	print("second resume :", "x")
	local r, s = coroutine.yield(a + c, a + b)

	print("third resume : ", r , s)
	return c
end)

print("main" ,coroutine.resume(co, 1, 9, 20))
print("--------------------------")
print("main", coroutine.resume(co, "x"))
print("--------------------------")
print("main",coroutine.resume(co, "r", "s"))
print("--------------------------")

print("main",coroutine.resume(co, "r", "s"))

输出

线程和协同程序区别

1、一个具有多线程的程序可以同时运行几个线程,但协同程序需要彼此协作运行

任意时刻只有一个 协同进程在运行

2.调度方式:线程由曹祖系统的调度器进行抢占式调度;协同进程时非抢占式调度,由程序员控制执行权

3、并发性:线程是并发执行的,多个线程可以同时运行在多个处理器核心上,或者通过时间片轮转在单个核心上切换执行。协同程序则是协作式的,只有一个协同程序处于运行状态,其他协同程序必须等待当前协同程序主动放弃执行权。

4、内存占用:线程通常需要独立的堆栈和上下文环境,因此线程的创建和销毁会带来额外的开销。而协同程序可以共享相同的堆栈和上下文,因此创建和销毁协同程序的开销较小。

5、数据共享:线程之间可以共享内存空间,但需要注意线程安全性和同步问题。协同程序通常通过参数传递和返回值来进行数据共享,不同协同程序之间的数据隔离性较好。

6、调试和错误处理:线程通常在调试和错误处理方面更复杂,因为多个线程之间的交互和并发执行可能导致难以调试的问题。协同程序则在调试和错误处理方面相对简单,因为它们是由程序员显式地控制执行流程的。

线程适用于并发执行场景,在多核处理器上利用并发性加快任务执行速度。

协同程序适用于需要协作和协调的场景,例如状态机、事件驱动编程或者协作式任务处理。

Lua文件I/O

Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。

  • 简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
  • 完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
file = io.open (filename , mode)

lua垃圾回收

Lua 采用了自动内存管理。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。

Lua 中面向对象

我们知道,对象由属性和方法组成。LUA中最基本的结构是table,所以需要用table来描述对象的属性。

lua 中的 function 可以用来表示方法。那么LUA中的类可以通过 table + function 模拟出来。

面向对象特征

  • 1) 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。
  • 2) 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。
  • 3) 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
  • 4)抽象:抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。

参考

https://www.runoob.com/lua/lua-modules-packages.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值