lua ~~~~~~~
参考文档:
https://www.runoob.com/lua/lua-data-types.html
https://www.w3cschool.cn/lua/
https://zhuanlan.zhihu.com/p/141875196
前言
之前写过一篇关于 redis调用lua脚本的博客,但是对于lua脚本如何编写我其实没有太多概念,为了扩展知识面,这里开始学习下lua脚本。
lua脚本应用场景很多,有些玩游戏的童鞋应该懂(手动狗头🤣)。学习基于上面几个基本教程。
Lua简介
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua特性:
- 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
- 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
- 其它特性
- 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
- 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
- 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
- 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。
tip: 任何代码最终都要被“翻译”成二进制的形式才能在计算机中执行。
有的编程语言,如 C/C++、Pascal、Go语言、汇编等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件,看不到源码。这个过程叫做编译(Compile),这样的编程语言叫做编译型语言,完成编译过程的软件叫做编译器(Compiler)。
而有的编程语言,如 Shell、JavaScript、Python、PHP等,需要一边执行一边翻译,不会生成任何可执行文件,用户必须拿到源码才能运行程序。程序运行后会即时翻译,翻译完一部分执行一部分,不用等到所有代码都翻译完。这个过程叫做解释,这样的编程语言叫做解释型语言或者脚本语言(Script),完成解释过程的软件叫做解释器。
编译型语言的优点是执行速度快、对硬件要求低、保密性好,适合开发操作系统、大型应用程序、数据库等。
脚本语言的优点是使用灵活、部署容易、跨平台性好,非常适合 Web 开发以及小工具的制作。
Lua 应用场景
- 游戏开发
- 独立应用脚本
- Web 应用脚本
- 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
- 安全系统,如入侵检测系统
Hello Jimmy
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
写一个简单的程序 Hello Jimmy
# 编写,复制下面的话
> vim helloJimmy.lua
print("Hello jimmy ")
# 执行文件
> lua helloJimmy.lua
基本语法
Lua 提供了交互式编程模式 lua -i
或 lua
来启用
> lua -i
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print("hello")
hello
脚本式编程(上面的hello jimmy),也可以将代码修改为如下形式来执行脚本(在开头添加:#!/usr/local/bin/lua)
#!/usr/bin/lua
print("hi JimmyMarking!")
以上代码中,我们指定了 Lua 的解释器 /usr/local/bin directory。加上 # 号标记解释器会忽略它。
> chmod +x hiJimmy.lua
> ./hiJimmy.lua
hi JimmyMarking!
注释:
- 单行注释
--
- 多行注释
--[[--]]
变量:Lua 标示符用于定义一个变量,函数获取其他用户定义的项。标示符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上0个或多个字母,下划线,数字(0到9)。最好不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。Lua 不允许使用特殊字符如 @, $, 和 % 来定义标示符。 Lua 是一个区分大小写的编程语言。因此在 Lua 中 W3c 与 w3c 是两个不同的标示符。
关键字&保留字:一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量
and | break | do | else |
elseif | end | false | for |
function | if | in | local |
nil | not | or | repeat |
return | then | true | until |
while |
全局变量
在默认情况下,变量总是认为是全局的。
全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。想删除一个全局变量,只需要将变量赋值为nil。
数据类型
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
Lua中有8个基本类型分别为:nil、boolean、number、string、userdata、function、thread和table。
数据类型 | 描述 |
---|---|
nil | 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean | 包含两个值:false和true。 |
number | 表示双精度类型的实浮点数,默认类型可以修改 luaconf.h 里的定义) |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路,用于执行协同程序 |
table | Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。 |
可以使用 type()
函数查看变量类型
print(type("Hello jimmy")) --> string
print(type(10.4*3)) --> number
print(type(print)) --> function
print(type(type)) --> function
print(type(true)) --> boolean
print(type(nil)) --> nil
print(type(type(X))) --> string
nil
使用 nil 作比较时应该加上双引号
> print(type(X))
nil
> print(type(x)==nil)
false
> print(type(X)=="nil")
true
number
Lua 默认只有一种 number 类型 – double(双精度)类型(默认类型可以修改 luaconf.h 里的定义),以下几种写法都被看作是 number 类型:
print(type(2))
print(type(2.2))
print(type(0.2))
print(type(2e+1))
print(type(0.2e-1))
print(type(7.8263692594256e-06))
String
-- 一对双引号或单引号
str = "my name is li lei"
ans = 'my name is han mei mei'
-- 2 个方括号[[]]
sql = [[
select * from test t where t.id ='1'
]]
-- 字符串计算(对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字)
"2" + 6
8
"jimmy" + 1
stdin:1: unexpected symbol near '"error"'
-- 字符串拼接
"a" .. 'b'
ab
-- 使用 # 来计算字符串的长度,放在字符串前面
print(#'jimmy')
5
table
在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表
# -- 创建一个空的 table
> a = {}
> a["name"] = "jimmy"
> print(a["name"])
jimmy
# -- 直接初始表
> music = {"渡雁", "天下局", "狂徒", "Rollercoaster"}
>example = { key1 = "val1", key2 = "val2", "val3" }
>for k, v in pairs(example) do
print(k .. " - " .. v)
end
# -- 下面是输出
1 - val3
key1 - val1
key2 - val2
finction
在 Lua 中,函数是被看作是第一类值(First-Class Value)
functionPrc.lua
function show(x)
if x == "nil" then
return 1
else
return x.."jimmy"
end
end
print(show('hello '))
print(show(a))
print('---------')
otherFuc = show
print(otherFuc('hello '))
print(otherFuc(a))
# 编辑脚本 复制上面的
> vim functionPrc.lua
# 执行
> lua functionPrc.lua
hello jimmy
lua: functionPrc.lua:5: attempt to concatenate local 'x' (a nil value)
stack traceback:
functionPrc.lua:5: in function 'show'
functionPrc.lua:10: in main chunk
[C]: ?
# 从结果来看是好像是 function输入的参数不能是 nil,将脚本中的 print(show(a)) print(otherFuc(a)) 注释掉后重新运行
> vim functionPrc.lua
> lua functionPrc.lua
hello jimmy
---------
hello jimmy
匿名函数
anonymityFunPrc.lua
function anonymous(tab, fun)
for k, v in pairs(tab) do
print(fun(k, v))
end
end
tab = { key1 = "val1", key2 = "val2" }
anonymous(tab, function(key, val)
return key .. " = " .. val
end)
-- 运行后结果
--[[
key1 = val1
key2 = val2
--]]
thread(线程)
在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。
userdata(自定义类型)
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。