Lua 閉包(Closure)

今天看到一個非常生動的使用閉包概念的代碼片段,決定記錄下來,這個代碼出自 Kong 的插件 rate-limiting :

function RateLimitingHandler:access(conf)
  -- ...

  kong.ctx.plugin.timer = function()
    local ok, err = timer_at(0, increment, conf, limits, identifier, current_timestamp, 1)
    if not ok then
      kong.log.err("failed to create timer: ", err)
    end
  end
end

function RateLimitingHandler:log(_)
  if kong.ctx.plugin.timer then
    kong.ctx.plugin.timer()
  end
end

在學習閉包概念的時候,對里面提到的一句話不是非常理解:閉包可以捕捉作用域內(nèi)的變量。一直沒有找到特別好的實際用例,在這個代碼片段里就能比較清晰的理解了。 access 階段聲明了一個延時函數(shù)的閉包,這個閉包在 log 階段進行調(diào)用。如果不用閉包的話,代碼會是什么樣子呢?

function RateLimitingHandler:access(conf)
  -- ...

  kong.ctx.plugin.limits = limits
  kong.ctx.plugin.identifier = identifier
  kong.ctx.plugin.timestamp = current_timestamp
end

function RateLimitingHandler:log(_)
  local limits = kong.ctx.plugin.limits
  local identifier = kong.ctx.plugin.identifier
  local current_timestamp = kong.ctx.plugin.timestamp

  local ok, err = timer_at(0, increment, conf, limits, identifier, current_timestamp, 1)
  if not ok then
    kong.log.err("failed to create timer: ", err)
  end
end

我們需要使用 kong.ctx.plugin 來在 access 和 log 階段之間共享變量,這樣代碼會顯得很臃腫,如果使用閉包進行作用域變量的捕捉,那么代碼就會寫得簡潔優(yōu)雅。

如何修改閉包內(nèi)的變量?這里我依然引用 Kong 2.x 的插件代碼,比方說我們要開發(fā)一個插件的 Admin API ,我們需要在插件目錄下創(chuàng)建 api.lua :

local endpoints = require "kong.api.endpoints"

local kong = kong
local caches_schema = kong.db.caches.schema

return {
  ["/caches"] = {
    schema = caches_schema,
    methods = {
      GET = endpoints.get_collection_endpoint(caches_schema),
    },
  },
  ["/caches/:cache_id"] = {
    schema = caches_schema,
    methods = {
      GET = function(self, ...)
        self.params.devices = { id = self.params.id }
        return endpoints.get_entity_endpoint(caches_schema)(self, ...)
      end,
    },
  },
}

首先看下這里的 get_collection_endpointget_entity_endpoint 方法是什么東西( kong/api/endpoints.lua ):

local function get_entity_endpoint(schema, foreign_schema, foreign_field_name, method, is_foreign_entity_endpoint)
  return function(self, db, helpers)
    -- ...
  end
end

可以看到,這里其實是返回了一個閉包,那么我們該如何修改這個閉包的參數(shù)呢?就是創(chuàng)建一個外部的函數(shù),在這個函數(shù)里調(diào)用這個閉包,從而修改:

GET = function(self, ...)
  self.params.caches = { id = self.params.id }
  return endpoints.get_entity_endpoint(caches_schema)(self, ...)
end,
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容