博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lua使用总结
阅读量:6511 次
发布时间:2019-06-24

本文共 8467 字,大约阅读时间需要 28 分钟。

hot3.png

Lua 环境安装

Linux环境安装

选择你需要的Lua版本:

curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gztar zxf lua-5.3.4.tar.gzcd lua-5.3.4make linux testmake install

测试安装环境错误:

cd src && make linuxmake[1]: Entering directory `/home/webapps/lua/lua-5.3.4/src'make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"make[2]: Entering directory `/home/webapps/lua/lua-5.3.4/src'gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lua.o lua.clua.c:82:31: 错误:readline/readline.h:没有那个文件或目录lua.c:83:30: 错误:readline/history.h:没有那个文件或目录lua.c: 在函数‘pushline’中:lua.c:312: 警告:隐式声明函数‘readline’lua.c:312: 警告:赋值时将整数赋给指针,未作类型转换lua.c: 在函数‘addreturn’中:lua.c:339: 警告:隐式声明函数‘add_history’make[2]: *** [lua.o] 错误 1make[2]: Leaving directory `/home/webapps/lua/lua-5.3.4/src'make[1]: *** [linux] 错误 2make[1]: Leaving directory `/home/webapps/lua/lua-5.3.4/src'make: *** [linux] 错误 2

解决方案:

yum install libtermcap-devel ncurses-devel libevent-devel readline-devel

安装成功:

lua -vLua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio

编写测试代码:

vi lua_coding.lua --新建文件print("Hello World Keep Coding!!!") --执行代码lua lua_coding.lua --执行

Windows 环境安装

Window 系统上安装 Lua window下你可以使用一个叫"SciTE"的IDE环境来执行lua程序,下载地址为:

  • 本站下载地址:
  • Github 下载地址:
  • Google Code下载地址 : 双击安装后即可在该环境下编写 Lua 程序并运行。

你也可以使用 Lua 官方推荐的方法使用 LuaDist:

国人开发IDEA Lua插件:

Lua语法

以下代码保存文件可以直接运行: 新建2个模块测试文件:TestMod.lua, TestLoad.lua

TestMod.lua 代码

local TestMod = {}local function getname()    return "无忌"endfunction TestMod.Greeting()    print("Hello, My name is "..getname())endreturn TestMod

TestLoad.lua 代码

print('load...')

测试代码:

print("Hello World Keep Coding!!!")--注释--[[多行注释--]]--[[变量NULL在Lua中是nillua中的变量如果没有特殊说明,全是全局变量,那怕是语句块或是函数里。变量前加local关键字的是局部变量--]]theGlobalVar = 50  --全局变量local theLocalVar = "local variable" --本地变量-- 5种方式定义的变量,字符串相等a1 = 'alo\n123"'a2 = "alo\n123\""a3 = '\97lo\10\04923"'a4 = [[alo123"]]    -- 多行变量定义的方式a5 = [===[alo123"]===]  -- [=[之间多少个==都没关系nullvar = nullprint('---- 变量 ----')print(a1 == a2)print(a2 == a3)print(a3 == a4)print(a4 == a5)print('nullvar == nil is',nullvar == nil)print('---- 变量 ----')print('---- 控制语句 ----')print('---- if-else分支 ----')io.write('请输入年龄:')local age = io.read("*number")io.read() -- 回车符io.write('请输入性别(男|女):')local sex = io.read()if age == 40 and sex =="男" then    print("男人四十一枝花")elseif age > 60 and sex ~="女" then    print("old man without country!")elseif age < 20 then    io.write("too young, too naive!\n")else    print("Your age is "..age)endprint('----  for循环 ----')sum = 0for i = 100, 1, -2 do    sum = sum + iendprint("sum =",sum)print('----  while循环 ----')-- Lua没有++或是+=这样的操作sum = 0num = 1while num <= 100 do    sum = sum + num    num = num + 1endprint("sum =",sum)print('----  until循环 ----')sum = 2repeat   sum = sum ^ 2 --幂操作   print('until循环 sum=',sum)until sum > 1000print('---- 控制语句 ----')print('\n---- 函数 与JavaScript 写法类似 ----')print('---- 递归 ----')function fib(n)  if n < 2 then return 1 end  return fib(n - 2) + fib(n - 1)endprint(fib(2))print('---- 闭包 ----')function newCounter()    local i = 0    return function()     -- anonymous function       i = i + 1        return i    endendc1 = newCounter()print(c1())  --> 1print(c1())  --> 2function myPower(x)    return function(y) return y^x endendpower2 = myPower(2)power3 = myPower(3)print('4的2次方=',power2(4)) --4的2次方print('5的3次方=',power3(5)) --5的3次方--函数的返回值,可以一次返回多个值function returnMultiParam()	return '无忌', 'nassir.wen@gmail.com', 40endprint('方法返回多个参数:',returnMultiParam())--局部函数 JavaScript类似function foo(x) return x^2 endfoo = function(x) return x^2 endprint('---- Table对象(支持Array 和 Map结构) ----')--所谓Table其实就是一个Key Value的数据结构,它很像Javascript中的Object,或是PHP中的数组,在别的语言里叫Dict或Maparr = {name='无忌',age=37,email='nassir.wen@gmail.com'}arr2 = {10,20,30} -- 等价于  {[1]=10,[2]=20,[3]=30}arr3 = {'无忌',function(x) return x + 1 end} -- 数组中可以定义不同类型,也可以定义方-- 遍历数组for k, v in pairs(arr) do    print(k, v)endfor i = 1, #arr2 do -- 数组下标从0开始, #arr2代表arr2长度	print(arr2[i])endprint('调用数组中的方法:',arr3[2](1))print('---- MetaTable 和 MetaMethod ----')-- MetaTable和MetaMethod是Lua中的重要的语法,MetaTable主要是用来做一些类似于C++重载操作符式的功能fraction_a = {numerator=2, denominator=3}  --分数 2/3fraction_b = {numerator=4, denominator=7}  --分数 4/7-- 如果直接执行 fraction_a + fraction_b 会报错,我们需要通过MetaTable处理-- 使用MetaTablefraction_op={}function fraction_op.__add(f1, f2)    ret = {}    ret.numerator = f1.numerator * f2.denominator + f2.numerator * f1.denominator    ret.denominator = f1.denominator * f2.denominator    return retend-- 为之前定义的两个table设置MetaTable:(其中的setmetatble是库函数)setmetatable(fraction_a, fraction_op)setmetatable(fraction_b, fraction_op)fraction_s = fraction_a + fraction_bprint('MateTable 实现分数对象相加:', fraction_s.numerator, '/' , fraction_s.denominator)print('---- 面向对象(有点像Javascript的prototype)----')--[[ 面向对象的实现,主要是使用MetaMethod的__index重载,所谓__index,说得明确一点,如果我们有两个对象a和b,我们想让b作为a的prototype只需要setmetatable(a, {__index = b})--]]Person={}function Person:new(p)    local obj = p    if (obj == nil) then        obj = {name="无忌", age=18, handsome=true}    end    self.__index = self    return setmetatable(obj, self)endfunction Person:toString()    return self.name .." : ".. self.age .." : ".. (self.handsome and "handsome" or "ugly")end--[[1)self 就是 Person,Person:new(p),相当于Person.new(self, p)2)new方法的self.__index = self 的意图是怕self被扩展后改写,所以,让其保持原样3)setmetatable这个函数返回的是第一个参数的值。--]]-- 测试me = Person:new()print(me:toString())kf = Person:new{name="King's fucking", age=70, handsome=false}print(kf:toString())-- 继承,同样使用setmetatableStudent = Person:new()function Student:new()    newObj = {year = 2013}    self.__index = self    return setmetatable(newObj, self)endfunction Student:toString()    return "Student : ".. self.year.." : " .. self.nameendstu = Student:new{name='无忌'}print('Student 继承:',stu:toString())print('---- 模块 ---- ')--[[加载文件几种方式区别:require("model_name") 载入相同文件只会执行一次dofile("model_name") 载入相同文件每次都会执行loadfile("model_name") 载入文件不执行,等你需要执行的时候再执行3种方式测试: 文件 TestLoad.luaprint('load...')--]]print('---- 测试require加载3次 ----')require('testload')require('testload')require('testload')print('---- 测试require加载3次 ----')print('---- 测试dofile加载3次 ----')dofile('testload.lua')dofile('TestLoad.lua')dofile('TestLoad.lua')print('---- 测试dofile加载3次 ----')print('---- 测试loadfile加载3次 ----')loadfile('testload')loadfile('testload')loadfile('testload')print('---- 测试loadfile加载3次 ----')-- 具体模块实现--[[ 模块名: TestMod.lualocal TestMod = {}local function getname()    return "无忌"endfunction TestMod.Greeting()    print("Hello, My name is "..getname())endreturn TestMod--]]-- 调用local test_mod = require("TestMod")test_mod.Greeting()

Lua + Redis集群 秒杀场景使用

实现逻辑:

  • 秒杀商品先保存在Redis
  • 确认下单资格,通过Lua脚本扣减库存,由于Redis是单线程模型,Lua可以保证多个命令原子性

初始化商品数据:

模拟数据格式:goodsId 商品ID,Total 商品总数,Booked 商品已预定数"goodsId" : {    "Total": 3    "Booked": 0}

执行redis初始化:

redis 127.0.0.1:6379> HMSET goodsId Total 3 Booked 0 OK redis 127.0.0.1:6379> HMGET goodsId Total Booked 1) "3" 2) "3"

Lua实现扣减库存脚本: seckill.lua

local n = tonumber(ARGV[1])if not n  or n == 0 then    return 0       end                local vals = redis.call('HMGET', KEYS[1], 'Total', 'Booked');local total = tonumber(vals[1])local blocked = tonumber(vals[2])if not total or not blocked then    return 0       end                if blocked + n <= total then    redis.call('HINCRBY', KEYS[1], 'Booked', n)                                      return n;   end                return 0

将扣减库存脚本加载到Redis:

./redis-cli SCRIPT LOAD "$(cat /usr/local/redis/bin/seckill.lua)"59dac41ffd27bef73ae87593da59b783b737a04b

执行扣减代码:

127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1(integer) 1127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1(integer) 1127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1(integer) 1127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1(integer) 0127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1(integer) 0127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1返回 1 扣减成功返回 0 扣减失败

执行函数说明

EVAL script numkeys key [key ...] arg [arg ...]

EVAL 执行脚本 key数量 key值 执行参数
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
EVALSHA 执行sha1效验值 key数量 key值 执行参数

每个被执行过的 Lua 脚本, 在 Lua 环境中都有一个和它相对应的函数, 函数的名字由 f_ 前缀加上 40 个字符长的 SHA1 校验和构成: 比如 f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91 。

只要脚本所对应的函数曾经在 Lua 里面定义过, 那么即使用户不知道脚本的内容本身, 也可以直接通过脚本的 SHA1 校验和来调用脚本所对应的函数, 从而达到执行脚本的目的 —— 这就是 EVALSHA 命令的实现原理。

参考

Lua环境搭建:

Lua简明教程(入厕文章):
Aliyun redis集群:
Redis中Lua脚本使用:

转载于:https://my.oschina.net/wenjinglian/blog/1823554

你可能感兴趣的文章
同意不同列多字段分组查询
查看>>
EL表达式各种函数使用大全
查看>>
hibernate注解bean的标准用法
查看>>
python查找中间值
查看>>
discuz x2 gzip压缩
查看>>
jquery选择器空格与大于号、加号与波浪号的区别~(原创)
查看>>
用Editplus开发Java
查看>>
nginx配置二级域名
查看>>
JDK并发编程2
查看>>
构建Dubbo服务的可执行jar包
查看>>
32G mysql db 优化
查看>>
百度人脸识别api实现及demo
查看>>
【原创】安装 CentOS 5.6 后启动无法进入图形界面
查看>>
【原创】Netflix 和 Chaos Monkey
查看>>
cname和CDN
查看>>
详解 RestTemplate 操作
查看>>
Android自定义吐司Toast:自定义样式、自定义显示时长
查看>>
任我行三 - 合并mytracks代码
查看>>
我的友情链接
查看>>
set_include_path的使用
查看>>