同事指着一份源码问我,老黄,你知道他们为什么要这么写代码么,我瞅过去,看到了如下代码:
- local get_upstream_by_id
- do
- ------------------------------------------------------------------------------
- -- Loads a single upstream entity.
- -- @param upstream_id string
- -- @return the upstream table, or nil+error
- local function load_upstream_into_memory(upstream_id)
- log(DEBUG, "fetching upstream: ", tostring(upstream_id))
-
- local upstream, err = singletons.db.upstreams:select({id = upstream_id})
- if not upstream then
- return nil, err
- end
-
- return upstream
- end
- _load_upstream_into_memory = load_upstream_into_memory
-
- get_upstream_by_id = function(upstream_id)
- local upstream_cache_key = "balancer:upstreams:" .. upstream_id
- return singletons.cache:get(upstream_cache_key, nil,
- load_upstream_into_memory, upstream_id)
- end
- end
他迷惑的是,为啥要写成这种 local xx do ... end 的格式。而且就上面这段代码来说,完全可以直接写成这样:
- ------------------------------------------------------------------------------
- -- Loads a single upstream entity.
- -- @param upstream_id string
- -- @return the upstream table, or nil+error
- local function load_upstream_into_memory(upstream_id)
- log(DEBUG, "fetching upstream: ", tostring(upstream_id))
-
- local upstream, err = singletons.db.upstreams:select({id = upstream_id})
- if not upstream then
- return nil, err
- end
-
- return upstream
- end
- _load_upstream_into_memory = load_upstream_into_memory
-
- local get_upstream_by_id = function(upstream_id)
- local upstream_cache_key = "balancer:upstreams:" .. upstream_id
- return singletons.cache:get(upstream_cache_key, nil,
- load_upstream_into_memory, upstream_id)
- end
前后两段从语义上并无二致。
因为单从 lua 的 do end 语法来看,do end 只是限定了本地变量的作用域,do end 内部定义的 local 变量,出了作用域就无法直接访问了(除了被闭包引用之外)。
从网络搜索,也基本印证这种说法:
问题是,刚开始的那段代码中的 do end 块中,并没有定义 local 变量啊,为啥还要这么写呢,我想,估计作者就是喜欢按照这个套路来,或者最早的代码中在do end中有local变量,或者后续代码功能增强或者重构后,也可能产生新的 local 变量,这样子 do end 的代码结构还可以保持不变。例如
- local get_upstream_by_id
- do
- local xx
- local yy
- -- ...
- end
只能说作者学了 do end 的一招鲜了,不管是不是有用,都套上一把。跟那种写JAVA,有的同学总是在方法开头声明所有变量一样,有点相同的意味。
We can delimit a block explicitly, bracketing it with the keywords do-end. These do blocks can be useful when you need finer control over the scope of one or more local variables:
- do
- local a2 = 2*a
- local d = sqrt(b^2 - 4*a*c)
- x1 = (-b + d)/a2
- x2 = (-b - d)/a2
- end -- scope of `a2' and `d' ends here
- print(x1, x2)
At times it is useful to further limit the scope of local variables with do-blocks [PIL 4.2]:
- local v
- do
- local x = u2*v3-u3*v2
- local y = u3*v1-u1*v3
- local z = u1*v2-u2*v1
- v = {x,y,z}
- end
-
- local count
- do
- local x = 0
- count = function() x = x + 1; return x end
- end
Global variables scope can be reduced as well via the Lua module system [PIL2 15] or [setfenv].