热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Lua使用总结

2019独角兽企业重金招聘Python工程师标准Lua环境安装Linux环境安装选择你需要的Lua版本:http:www.lua.orgftpcurl-R-Oh



2019独角兽企业重金招聘Python工程师标准>>> hot3.png



lua+redis


Lua 环境安装


Linux环境安装


选择你需要的Lua版本:http://www.lua.org/ftp/


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

测试安装环境错误:


cd src && make linux
make[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.c
lua.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] 错误 1
make[2]: Leaving directory `/home/webapps/lua/lua-5.3.4/src'
make[1]: *** [linux] 错误 2
make[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 -v
Lua 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程序,下载地址为:


  • 本站下载地址:LuaForWindows_v5.1.4-46.exe
  • Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases
  • Google Code下载地址 : https://code.google.com/p/luaforwindows/downloads/list 双击安装后即可在该环境下编写 Lua 程序并运行。

你也可以使用 Lua 官方推荐的方法使用 LuaDist:http://luadist.org/


国人开发IDEA Lua插件:https://github.com/tangzx/IntelliJ-EmmyLua


Lua语法



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



TestMod.lua 代码


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

TestLoad.lua 代码


print('load...')

测试代码:


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

Lua &#43; Redis集群 秒杀场景使用


实现逻辑&#xff1a;


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

初始化商品数据&#xff1a;


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

执行redis初始化&#xff1a;


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 &#61; tonumber(ARGV[1])
if not n or n &#61;&#61; 0 then
return 0
end
local vals &#61; redis.call(&#39;HMGET&#39;, KEYS[1], &#39;Total&#39;, &#39;Booked&#39;);
local total &#61; tonumber(vals[1])
local blocked &#61; tonumber(vals[2])
if not total or not blocked then
return 0
end
if blocked &#43; n <&#61; total then
redis.call(&#39;HINCRBY&#39;, KEYS[1], &#39;Booked&#39;, n)
return n;
end
return 0

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


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

执行扣减代码&#xff1a;


127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 1
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 1
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 1
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 0
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 0
127.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 脚本&#xff0c; 在 Lua 环境中都有一个和它相对应的函数&#xff0c; 函数的名字由 f_ 前缀加上 40 个字符长的 SHA1 校验和构成&#xff1a; 比如 f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91 。


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


参考


Lua环境搭建&#xff1a;http://www.runoob.com/lua/lua-environment.html
Lua简明教程(入厕文章)&#xff1a;https://coolshell.cn/articles/10739.html
Aliyun redis集群: https://help.aliyun.com/document_detail/63920.html?spm&#61;a2c4g.11186623.6.611.A4j6rw
Redis中Lua脚本使用: http://redisbook.readthedocs.io/en/latest/feature/scripting.html







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



推荐阅读
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • window下的python安装插件,Go语言社区,Golang程序员人脉社 ... [详细]
  • 最近遇到了一道关于哈夫曼树的编程题目,需要在下午之前完成。题目要求设计一个哈夫曼编码和解码系统,能够反复显示和处理多个项目,直到用户选择退出。希望各位大神能够提供帮助。 ... [详细]
  • 本文整理了关于Sia去中心化存储平台的重要网址和资源,旨在为研究者和用户提供全面的信息支持。 ... [详细]
  • 本文整理了一份基础的嵌入式Linux工程师笔试题,涵盖填空题、编程题和简答题,旨在帮助考生更好地准备考试。 ... [详细]
  • 本文介绍了如何使用Python爬取妙笔阁小说网仙侠系列中所有小说的信息,并将其保存为TXT和CSV格式。主要内容包括如何构造请求头以避免被网站封禁,以及如何利用XPath解析HTML并提取所需信息。 ... [详细]
  • 本文详细探讨了使用Python3编写爬虫时如何应对网站的反爬虫机制,通过实例讲解了如何模拟浏览器访问,帮助读者更好地理解和应用相关技术。 ... [详细]
  • python模块之正则
    re模块可以读懂你写的正则表达式根据你写的表达式去执行任务用re去操作正则正则表达式使用一些规则来检测一些字符串是否符合个人要求,从一段字符串中找到符合要求的内容。在 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • C#实现文件的压缩与解压
    2019独角兽企业重金招聘Python工程师标准一、准备工作1、下载ICSharpCode.SharpZipLib.dll文件2、项目中引用这个dll二、文件压缩与解压共用类 ... [详细]
  • Spring Data JdbcTemplate 入门指南
    本文将介绍如何使用 Spring JdbcTemplate 进行数据库操作,包括查询和插入数据。我们将通过一个学生表的示例来演示具体步骤。 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • 在IIS上运行的WebApi应用程序在开发环境中能够正常进行文件的读写操作。然而,在尝试通过FTP访问实时服务器上的文件列表时,遇到了无法显示的问题,尽管服务器配置与开发环境相同。这可能涉及权限设置、FTP服务配置或网络连接等方面的问题。 ... [详细]
author-avatar
锦瑟刻下两段缠绵
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有