說點什么
上次介紹了一個較為嚴格的 Lua 數組的實現——LuaArray,這次奉上 LuaHashMap 的實現。當然,機制和LuaArray 一樣,我們就不介紹了。
基本要求
- 除了
nil
,任何值都可以作為鍵; - 可通過鍵直接訪問和修改值;
- 對不存在的鍵進行賦值將創建新的鍵值對映射;
- 可開啟鍵值數據類型過濾,即類似嚴格類型映射:
HashMap(String, String)
,非匹配的鍵值映射將被過濾或做無效處理; - 提供基本的方法來操作鍵值對。
硬性約束
- 不允許直接修改內置的方法,如有需要,請手動擴展
__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 中的鍵值對類型一致,需要對映射表開啟類型檢查和過濾。在構造的時候,可以傳入鍵值的類型ktype
、vtype
,默認ktype
、vtype
都為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: