zoukankan      html  css  js  c++  java
  • lua 使用中遇到的坑总结

    前言

    竹子是 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)

    看运行结果:

    2018/02/01 07:48:40 [error] 753#0: *766 lua entry thread aborted: runtime error: /app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:182: 
    attempt to perform arithmetic on a string value 在 string 类型的数据上执行算术运算,所以肯定报错了,心累) stack traceback: coroutine
    0: /app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua: in function </app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:1>,
    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,发现报下面的错

    2018/02/01 08:00:46 [error] 772#0: *772 lua entry thread aborted: runtime error: /app/lua_pro/lua_exercise/util/util1.lua:10: 
    attempt to concatenate local 'address' (a nil value) stack traceback: coroutine 0: /app/lua_pro/lua_exercise/util/util1.lua: in function 'tt1' /app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:191: in function </app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:1>,
    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:

    2018/02/01 08:44:43 [error] 782#0: *774 lua entry thread aborted: runtime error: /app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:199: 
    attempt to concatenate local 'str' (a nil value) stack traceback: coroutine 0:/app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua: in function </app/lua_pro/lua_exercise/mobile_login_exercise/ng_test.lua:1>,
    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 = 0
    
    boolean
    local flag = true
    
    and so on .....

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

    local return_result = func()
    return_result = (return_result and {return_result} or {''})[1]
    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 = 0
    for k in pairs(_tab) do
        i = i + 1
    end

    --循环取值 local msg = '' for n = 1, 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 = 0
    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 也不对呢,但是我们要的拼接字符串,为空我们就不拼接了嘛,对吧,也想当于是实现我们要的效果了嘛。哈哈。

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

  • 相关阅读:
    HashMap和HashSet的区别
    安卓坐标
    android MotionEvent中getX()和getRawX()的区别
    android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明
    register_chrdev_region/alloc_chrdev_region和cdev注册字符设备驱动
    将JZ2440的调试串口换成com2
    pcl点云文件格式
    C++中的迭代器
    C++中的vector
    “标准差”
  • 原文地址:https://www.cnblogs.com/zhuzi91/p/8392385.html
Copyright © 2011-2022 走看看