Lua string.find 中的 “坑”

2.7k 词
			<p>我们的线上环境,ngx_lua api 都是以模块形式加载到 lua 级别的 vm 中,已达到最大性能。而且我们并没有使用传统的 “包” 的形式来加载(也就是 <code class="highlighter-rouge">require "xx.xx.xx"</code> ),而是直接以模块名为加载( <code class="highlighter-rouge">require "xx"</code> ),这就意味着我们需要不断的来动态设置 <code class="highlighter-rouge">package.path</code> 来配合 <code class="highlighter-rouge">require</code> 的机制。于是我们写了下面这个方法,来实现我们的需求:</p>
function tools:loadluapath(root_path)
    if root_path == nil then
        return
    end
<span class="kd">local</span> <span class="n">root_path</span> <span class="o">=</span> <span class="n">root_path</span> <span class="o">..</span> <span class="s2">"/?.lua;"</span>
<span class="k">if</span> <span class="nb">string.find</span><span class="p">(</span><span class="nb">package.path</span><span class="p">,</span><span class="n">root_path</span><span class="p">)</span> <span class="o">==</span> <span class="kc">nil</span> <span class="k">then</span>
    <span class="nb">package.path</span> <span class="o">=</span> <span class="nb">package.path</span> <span class="o">..</span> <span class="n">root_path</span>
<span class="k">end</span>

end

但近期我却发现 package.path 好像存在泄漏点,有将近 60K 的大小,而且还在一直持续增长。这并不符合我们的预期,其应该是在启动阶段过后,在一段时间内不断增长,之后应该是趋于稳定,到最后完全是一个常数级的大小。所以说,上面的 loadluapath 方法一定是出了问题,那么肯定就是 string.find(package.path,root_path) == nil 这条语句喽,继续测试:

Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
>
>
> do
>>     print(package.path)
>>     print(string.rep("=",20))
>>     print(string.find(package.path,"/test/yyyy-mm-dd/?.lua"))
>> end
./?.lua;
/usr/local/lua/share/lua/5.1/?.lua;/usr/share/lua/5.1/?.lua;
/usr/share/lua/5.1/?/init.lua;/usr/lib64/lua/5.1/?.lua;
/usr/lib64/lua/5.1/?/init.lua;
/test/yyyy-mm-dd/?.lua
====================
nil
>
>

貌似不对,为什么 string.find 返回 nil,又是万能的 SO 上找到了解释:

原来 string.find 是当做 pattern 来查找的。修改一下,继续测试:

>
> do
>>     print(package.path)
>>     print(string.rep("=",20))
>>     print(string.find(package.path,"/test/yyyy-mm-dd/?.lua",1,true))
>> end
./?.lua;
/usr/local/lua/share/lua/5.1/?.lua;/usr/share/lua/5.1/?.lua;
/usr/share/lua/5.1/?/init.lua;/usr/lib64/lua/5.1/?.lua;
/usr/lib64/lua/5.1/?/init.lua;
/test/yyyy-mm-dd/?.lua
====================
162 183

Bingo ! 这下看到预期效果了。

如果你也不确定 find 的字符串会不会包含元字符,靠谱的方式,还是加个 true 参数比较好!