[LuaHashMap] 嚴格的 Lua HashMap 實現

說點什么

上次介紹了一個較為嚴格的 Lua 數組的實現——LuaArray,這次奉上 LuaHashMap 的實現。當然,機制和LuaArray 一樣,我們就不介紹了。

基本要求

  1. 除了nil,任何值都可以作為鍵;
  2. 可通過鍵直接訪問和修改值;
  3. 對不存在的鍵進行賦值將創建新的鍵值對映射;
  4. 可開啟鍵值數據類型過濾,即類似嚴格類型映射: HashMap(String, String),非匹配的鍵值映射將被過濾或做無效處理;
  5. 提供基本的方法來操作鍵值對。

硬性約束

  1. 不允許直接修改內置的方法,如有需要,請手動擴展 __methods__ 列表;

實現

** 1. 構造 **
LuaArray ,首先我們需要創建一個 HashMap 的改造方法Map(),其中約定 new_map 為構造返回的 HashMap 實例, __map__用于存儲鍵值對映射,__methods__ 用于存儲內置的鍵值對映射的操作方法:

function Map()
    local new_map = {}
    local __map__ = {}
    local __methods__ = {}
    -- do something to construct a map
    return new_map
end

** 2. 元表 **
元表需要提供了訪問映射表和內置方法的途徑,以及新增或修改一對映射的流程:

function Map()
    local new_map = {}
    local __map__ = {}
    local __methods__ = {}

    local mt = {
        __index = function(t, k)
            -- 可以獲得根據鍵獲得值
            if __map__[k] then
                return __map__[k]
            end
            -- 可以獲得內置方法
            if __methods__[k] then
                return __methods__[k]
            end
        end,
        __newindex = function(t, k, v)
            -- 首先檢查內置方法列表中是否存在對應鍵,
            -- 為了避免思維的理解誤區,我們不建議在
            -- __map__中存儲與__methods__的同名映射
            if __methods__[k] then
                print('[warning] can not override native method.')
                return
            end
            -- set 方法用于設置鍵值對映射,我們后面再說明
            __methods__:set(k, v)
        end
    }
    setmetatable(new_map, mt)

    return new_map
end

** 3. 類型過濾**
鍵值對都有類型,為了保持HashMap 中的鍵值對類型一致,需要對映射表開啟類型檢查和過濾。在構造的時候,可以傳入鍵值的類型ktypevtype,默認ktypevtype都為Mixed(混合,也就是原生態的 lua table了),接下來只要對類型進行過濾即可:

-- 表長度
function table.len(tbl)
    local count = 0
    for k, v in pairs(tbl) do
        count = count + 1
    end
    return count
end

-- 打印表
function table.print(tbl)
    local format = string.format
    for k,v in pairs(tbl) do
        print(format('[%s] => ', k), v)
    end
end

-- 以鍵作為值來構造表
function table.keyAsValue(...)
    local arr = {...}
    local ret = {}
    for _,v in ipairs(arr) do
        ret[v] = v
    end
    return ret
end

-- 數據類型定義
DATA_TYPE = table.keyAsValue('boolean', 'number', 'string', 'function', 'table', 'thread', 'nil')

-- 檢查HashMap 的鍵值類型
local function checkHashType(tp)
    if not (tp == 'Mixed' or DATA_TYPE[tp]) then
        tp = 'Mixed'
    end
    return tp
end

-- HashMap 構造
function Map(ktype, vtype)
    local new_map = {}
    local __map__ = {}
    local __methods__ = {}
    local __key_type__, __value_type__ = checkHashType(ktype), checkHashType(vtype)

    -- 映射表類型
    function __methods__:typeOf()
        return string.format('HashMap<%s, %s>',__key_type__,__value_type__)
    end
    -- 映射表長度
    function __methods__:len()
        return table.len(__map__)
    end
    -- 設置一個映射
    function __methods__:set(k, v)
        -- 需要檢查映射表類型
        if (__key_type__ == 'Mixed' or type(k) == __key_type__)
        and (__value_type__ == 'Mixed' or type(v) == __value_type__) then
            __map__[k] = v
        end
    end
    -- 解除一個映射
    function __methods__:unset(k)
        __map__[k] = nil
    end
    -- 打印映射表
    function __methods__:print()
        table.print(__map__)
    end
    -- 過濾鍵類型
    function __methods__:filterKey(tp)
        print('filter key type:',tp)
        for k,v in pairs(__map__) do
            if not checkType(type(k), tp) then
                __map__[k] = nil
            end
        end
    end
    -- 過濾值類型
    function __methods__:filterValue(tp)
        print('filter value type:',tp)
        for k,v in pairs(__map__) do
            if not checkType(type(v), tp) then
                __map__[k] = nil
            end
        end
    end
    -- 設置鍵類型
    function __methods__:setKeyType(type)
        if not checkType(type, nil) then
            if __key_type__ == type then
                return
            end
            __key_type__ = type
            self:filterKey(type)
        end
    end
    -- 設置值類型
    function __methods__:setValueType(type)
        if not checkType(type, nil) then
            if __value_type__ == type then
                return
            end
            __value_type__ = type
            self:filterValue(type)
        end
    end
    -- 過濾值
    function __methods__:filter(val)
        for k,v in pairs(__map__) do
            if v == val then
                __map[k] = nil
            end
        end
    end

    -- 元表
    local mt = {
        __index = function(t, k)
            if __map__[k] then
                return __map__[k]
            end
            if __methods__[k] then
                return __methods__[k]
            end
        end,
        __newindex = function(t, k, v)
            -- 首先檢查內置方法列表中是否存在對應鍵,
            -- 為了避免思維的理解誤區,我們不建議在
            -- __map__中存儲與__methods__的同名映射
            if __methods__[k] then
                print('[warning] can not override native method.')
                return
            end
            -- 設置映射時需要檢查映射類型
            __methods__:set(k, v)
        end
    }
    setmetatable(new_map, mt)

    return new_map
end

以上。

PS:

  1. 在線測試
  2. 完整代碼
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容