使用不同的Lua库中相同名称的函数

我有两个用Lua编写的不同库,但拥有相同的函数名称。

如何在不修改库源代码的情况下选择其中一个?

require ('A') --A库
require ('B') --B库
test() --来自B的函数

如果我想要来自A的test函数,我该怎么做?

这里是一些我尝试过的方法。

  1. LuaJ loading two functions with the same name from two different LuaScripts

    我找到了这个,但是我不想修改库源代码。

  2. 将函数保存为不同的名称,例如:

    require ('A') --A库
    _G.testA = test
    require ('B') --B库
    _G.testB = test
    
    testA() --来自A的函数
    testB() --来自B的函数
    

    但是,如果有一天出现了一个新的函数名testA()或testB(),它会再次破坏。

    而且我仍然需要将所有现有的test()更改为testA()或testB()。

    有更好的方法吗?

点赞
用户1484669
用户1484669

你所描述的代码

require ('A') --A lib
_G.testA = test
require ('B') --B lib
_G.testB = test

testA() -- function from A
testB() -- function from B

绝对是解决你问题的一种方法。

为了避免未来问题,你可以将新函数放到 map 内部

-- Example library.lua

-- Old code not in map
function my_old_func(params)
    -- do some stuff
end

-- New code goes down here
local mylibrary = {}
function mylibrary:my_awesome_func(params)
    my_old_func(params)
end
2015-08-25 00:49:10
用户3677376
用户3677376

这正是为什么 Lua 模块不应设置全局变量的原因,而是应该将其所有函数/变量导出为一个表,通过 require 返回。

然而,如果你的两个模块都是 Lua 模块,你可以为每个模块设置一个自定义环境,以便模块定义的全局变量最终在不同的表中结束:

#!/usr/bin/lua

-- Lua 5.1 的 package.searchpath 回退实现
local searchpath = package.searchpath
-- 如果你使用的是 Lua 5.2+,则不需要:
if not searchpath then
  local delim = package.config:match( "^(.-)\n" ):gsub( "%%", "%%%%" )

  function searchpath( name, path )
    local pname = name:gsub( "%.", delim ):gsub( "%%", "%%%%" )
    local msg = {}
    for subpath in path:gmatch( "[^;]+" ) do
      local fpath = subpath:gsub( "%?", pname )
      local f = io.open( fpath, "r" )
      if f then
        f:close()
        return fpath
      end
      msg[ #msg+1 ] = "\n\tnofile '"..fpath.."'"
    end
    return nil, table.concat( msg )
  end
end

-- 存储每个模块的环境表的表
local environments = {}

-- 标准 Lua searcher 的副本,该 searcher 为加载的 chunk 设置一个自定义环境,
-- 并将其存储在环境表中。
local function my_lua_searcher( modname )
  local fpath, msg = searchpath( modname, package.path )
  if not fpath then
    return msg
  end
  local env = setmetatable( {}, { __index = _G } )
  env._G = env
  environments[ modname ] = env
  local f = assert( loadfile( fpath, nil, env ) )
  if setfenv then -- 对于 Lua 5.1
    setfenv( f, env )
  end
  return f, fpath
end

-- 替换 Lua searcher(在索引 2)
local searchers = package.searchers or package.loaders
-- 如果其他人增加了 package.searchers,我们无法知道
-- 我们要替换的是哪个函数的 Lua searcher:
assert( #searchers == 4, "package.searchers has been modified" )
searchers[ 2 ] = my_lua_searcher

-- 测试一下:
require( "A" )
require( "B" )
environments[ "A" ].test()
environments[ "B" ].test()
2015-08-25 01:16:55