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 也不對呢,但是我們要的拼接字符串,為空我們就不拼接了嘛,對吧,也想當於是實現我們要的效果了嘛。哈哈。

   當然還有很多,今天先寫到這里,以后有新的會補充進去。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM