前言

竹子是 java 程序员一枚,最近在做一个登录的改造,用 lua 实现,现在基本算是告一段落,然后在此分享下在过程中遇到的坑吧。

一定要注意使用 lua 的版本,版本不同,可能有的函数就没有了,比如 bit 中的 math.mod 函数,5.1 之后就改为 fmod() 了,但是当时引入的还是之前的版本,就报错了,报错了,但是还找了好久的错误,也是醉了。这些可以参考 lua 官网的发布说明,看看每个版本的发布说明 。

http://www.lua.org/manual/5.1/manual.html#7.2

1.字符串拼接(不是 + 而是 "..")

做过java 的都知道,java 中字符串的拼接使用 + ,但是在 lua 里千万要注意,不是"+", "+" 在 Lua 里只表示算术运算,真正的拼接字符串是 ".."

看实例:

local str = "Hello," + 'bamboo'
ngx.say(str)

看运行结果:

// :: [error] #: * lua entry thread aborted: runtime error: /app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:: 
attempt to perform arithmetic on a string value (在 string 类型的数据上执行算术运算,所以肯定报错了,心累)
stack traceback:
coroutine :
/app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua: in function </app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:>,
client: 172.17.0.1, server: localhost, request: "GET /ng_test HTTP/1.1", host: "localhost:8008"

这个一定要注意,竹子就是因为不注意,出了多次错,做为 java 程序员,这就是顺手的事呀。哈哈....

2.方法的调用 "." 和 ":"

这个也是很容易出错的地方,因为方法调用的时候用了".",而没有用 ":",出了好多次问题,宝宝心里苦呀,有的时候用 ".",有的时候用 ":",宝宝容易晕呀,有没有。不说了,来看例子.

ng_test.lua

local util1 = require 'util1'
ngx.say(util1.tt2('bamboo', 'Beijing'))

util1.lua

local _M = {}

function _M.tt1(name, address)
return 'user:' .. name .. ',address:' .. address
end function _M:tt2(name, address)
return 'user:' .. name .. ',address:' .. address
end
return _M

然后运行 nginx,发现报下面的错

// :: [error] #: * lua entry thread aborted: runtime error: /app/lua_pro/lua_exercise/util/util1.lua:: 
attempt to concatenate local 'address' (a nil value)
stack traceback:
coroutine :
/app/lua_pro/lua_exercise/util/util1.lua: in function 'tt1'
/app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:: in function </app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:>,
client: 172.17.0.1, server: localhost, request: "GET /ng_test HTTP/1.1", host: "localhost:8008"

wtf, address is nil,kidding me? 那到底是怎么回事呢,其实如果细心的话,会发现有 tt1 和 tt2 两个函数,然后 tt1 声明的时候用的是 ".",tt2 声明的时候用的是":"

>带点号的函数声明: ".",默认是没有 self 参数的

>冒号声明的函数,默认有一个隐藏的参数  self,so 在你调用的时候要用 ":",而不是 "."

因为正确的应该是  util1:tt2('Hello,', 'bamboo')

当然你调用 tt1 的时候直接 util1.tt1('Hello,', 'bamboo')即可。

关于 "." 和 ":" 的区别可以看看这里:https://www.lua.org/pil/16.html

tips:

我的经验是,用冒号声明,就用冒号调用;用点号声明,就用点号调用.保持一致,一般情况下喜欢用冒号声明,因为有一个 self 可以很方便的使用,上面给的链接中也涉及到了self 的用处。

3. nil 这个值是最令人头疼的问题了

  大家应该都知道,在代码中经常涉及到字符串、变量的拼接,但是有的时候可能变量会为空,也就是 nil,然后我们拼接了 nil 值,程序立马报错。这就尴尬了,而且 lua 的异常处理机制跟 java 比起来还是要差了很多。先不说异常处理,我说先说 nil 处理吧

  ng_test.lua

-- if you haven't assigned a default value to a variable,it is nil.After that,you concat it with a string value,so definitely, it will occur exception
local str
ngx.say("Hello" .. str)

 exception code:

// :: [error] #: * lua entry thread aborted: runtime error: /app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:: 
attempt to concatenate local 'str' (a nil value) stack traceback:
coroutine :/app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua: in function </app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:>,
client: 172.17.0.1, server: localhost, request: "GET /ng_test HTTP/1.1", host: "localhost:8008"

  一个变量,你没有赋默认值,他就是 nil,所以一般情况下最好根据类型赋个默认值,

比如 table
local tmp_tab = {} string
local str = '' number
local n = boolean
local flag = true and so on .....

  当然有的时候我们通过函数返回一个值,我们可以做个三元表达式,避免 nil 异常.

local return_result = func()
return_result = (return_result and {return_result} or {''})[]
return 'Hello,' .. return_result

  所以,我们最好每个返回值做拼接的时候加上三元表达式的判断

4. table 循环的时候遇到 nil 值会截断,而且不按照他原始的顺序输出

  来,直接看 demo 吧

  

local _tab = {
log_param1 = 'hello,',
log_param2 = 'nice to meet you.',
log_param3 = nil,
log_param4 = 'How are you?',
}
for k, v in pairs(_tab) do local tmp_v = v if not tmp_v then tmp_v = '' end ngx.say('k:' .. k .. ',v:' .. v .. '<br/>') end --输出,可以看到并不是 1 2 4 的输出,而是 1 4 2,我要根据传递的参数来,拼接日志,日志--是要求顺序的,这样肯定是不行的。 --k:log_param1,v:hello,
--k:log_param4,v:How are you?
--k:log_param2,v:nice to meet you.

  所以我们来尝试按照正常顺序获取值,如果遇到 nil,我们就拼接空嘛,但是顺序不对,那肯定是不行的了。(可能有的人说,那可以直接指定好变量名呢,不是更方便嘛,但是你要知道,这个是一个公共的方法,传递的参数个数是不确定,也不是确定的变量名,so 我们继续我们的 solution)

  

--计算 tab 的长度
local i =
for k in pairs(_tab) do
i = i +
end --循环取值
local msg = ''
for n = , i do
local tmp_v = _tab['log_param' .. n] if not tmp_v then
tmp_v = ''
end msg = msg .. tmp_v
end
ngx.say(msg) --输出,不对呀,按照我们的预想,应该是 Hello,nice to meet you.How are you?怎么不一--样呢
hello,nice to meet you.
--其实取 _tab 长度 i 的时候就取错了,取的是 3 而不是 4 ,所以了肯定不对。那我们要怎么做呢?

  看下面:

local i =
for k in pairs(_tab) do
k = tostring(k)
local index = ngx.re.find(k, '([0-9]+)', 'jo')
local tmp_k = string.sub(k, index, #k)
tmp_k = tonumber(tmp_k)
if tmp_k then
if i < tmp_k then
i = tmp_k
end
end
end
ngx.say('i is:' .. i .. '<br/>')

  改成这样之后就可以了,可能有的人又会问了,如果最后一个是 nil,那获取到的最大值是 3 也不对呢,但是我们要的拼接字符串,为空我们就不拼接了嘛,对吧,也想当于是实现我们要的效果了嘛。哈哈。

  当然还有很多,今天先写到这里,以后有新的会补充进去。

lua 使用中遇到的坑总结的更多相关文章

  1. sql server全文索引使用中的小坑

    一.业务场景 我们在实际生产环境中遇到了这样一种需求,即需要检索一个父子关系的子树数据 估计大家也遇到过类似的场景,最典型的就是省市数据,其中path字段是按层级关系生成的行政区路径: 如果我们已知某 ...

  2. Volly框架的使用基础版及使用中的一些坑 Ace 网络篇(三)

    直接把注释粘过来: * Volley使用讲解: * 要实现网络数据请求主要要记住下面三步骤: * 1.创建RequestQueue对象 * 2.创建XXRequest对象(XX代表String,JSO ...

  3. c#参数传递使用中的一个坑,值传递与引用传递

    c#参数传递使用中发现的一个问题 写了3个重载方法,把 对象.int .(int直接封入object) 传入SWAP方法进行数据操作结果对象内的数据发生了改变,其他2个没有:

  4. sql server全文索引使用中的小坑 (转载)

    一.业务场景 我们在实际生产环境中遇到了这样一种需求,即需要检索一个父子关系的子树数据 估计大家也遇到过类似的场景,最典型的就是省市数据,其中path字段是按层级关系生成的行政区路径: 如果我们已知某 ...

  5. DWZ使用中遇到的坑

    DWZ官方文档中关于文件上传表单的提交: 因为Ajax不支持enctype="multipart/form-data" 所以用隐藏iframe来处理无刷新表单提交. <for ...

  6. spring cloud zuul在使用中遇到的坑 : 转发时自动去掉prefix

    在使用zuul的时候遇到的坑总结一下: 逐渐增加更新以后遇到的 1.在路由的时候莫名其妙的把serviceId给去掉,导致404.比如请求:/serviceId/search/book,zuul会把s ...

  7. Maven学习(六)maven使用中遇到的坑

    坑1:使用eclipse构建web项目时,pom.xml中 <packaging>war</packaging> 报错 eclipse给出的报错信息提示是:web.xml is ...

  8. kubernetes使用中遇到的坑

    随着kubernetes的发展现在使用的范围越来越广,在使用过程中碰到问题是避免不了的,有些时候一些坑能提前避免是最好的,下面我做一个小记录,把我们生产环境中遇到的坑总结下,方便后面查询同时也方便各位 ...

  9. 解决 mklink 使用中的各种坑(硬链接,软链接/符号链接,目录链接)

    通过 mklink 命令可以创建文件或文件夹的链接,而这种链接跟快捷方式是不一样的.然而我们还可能会遇到其使用过程中的一些坑,本文将整理这些坑并提供解决方法.   0x00 背景介绍:mklink m ...

随机推荐

  1. 128bit 整数运算的实现

    对于128bit的长整型运算,GCC提供了扩展类型:__int128.然而该类型不在C/C++语言的标准之中,并且对于不同种类的编译器,它的实现情况不同.因此,在编写相关的可移植程序时,我们有必要实现 ...

  2. 阿里云-CentOS如何挂载硬盘

    阿里云CentOS挂载硬盘 查看当前未挂载的硬盘 # fdisk -l 创建硬盘分区 # fdisk /dev/vdb 根据提示,依次输入"n","p" &qu ...

  3. leetcode 动态规划类型题

    1,Triangle int mininumTotal(vector<vector<int>>& triangle) { ; i >= ; --i) { ; j ...

  4. PowerScript表达式

    运算符 算术运算符 双目运算符 运算符 名称 示例 说明 ^ 乘方 3^2   + 加 i_age+1   - 减 i_age - 1   * 乘 l_w*3   / 除 i_w/3   = 赋值 i ...

  5. Smartforms

    Include text Populate indicator in program perform get_text using '0002' ls_detail-vbeln"Header ...

  6. 20164319 刘蕴哲 Exp2 后门原理与实践

    [后门概念] 后门就是不经过正常认证流程而访问系统的通道. 特指潜伏于操作系统中专门做后门的一个程序,而“坏人”可以连接这个程序远程执行各种指令. (概念和木马有重叠) [学习内容] 使用nc实现wi ...

  7. Openssl asn1parse命令

    一.简介 asn1parse命令是一种用来诊断ASN.1结构的工具,也能用于从ASN1.1数据中提取数据 二.语法 openssl asn1parse [-inform PEM|DER] [-in f ...

  8. Python处理word文件

    python对word文件进行读写和复制 import win32conimport win32com.clientimport os #读取word文件def readWoldFile(path): ...

  9. Linux vim常见使用详解

    教你用Vim编辑器 1.Vim编辑器基本使用方法 光标移动 查找/替换 插入模式 复制/粘贴 复制/粘贴 2.vim打开时的警告信息 当使用vim打开一个文件时,会同时在该目录下创建个.filenam ...

  10. Python批量执行oracle中的insert语句

    从oracle导出一个表的数据,导出的格式是insert语句,数据量30万. 直接在PL/SQL Developer中执行,速度非常慢,脚本中也是100条数据提交一次.因为需要的时间太长,每次中断后, ...