如何在Lua中检查模块是否存在?

9
我正在使用 xdg-menu-to-awesome-wm生成一个包含 GNOME 菜单的 Lua 文件,以便在 Awesome WM 中进行 包含。由于生成器脚本可能未安装,因此我需要一种方法,让 Lua 只有在 menu 模块存在时才 require 它。
我不想查找文件名,因为它可能在package.path的任何地方。一种选择是忽略模块不存在时创建的异常,但我不想忽略任何其他异常 - 我希望知道该模块是否包含任何语法或其他错误。不幸的是,reference没有指定可以生成哪些异常,所以我不确定该如何做。

今天刚遇到了这个问题,有点震惊于答案部分有多少人似乎没有意识到模块未被找到与模块存在但具有语法错误不是同一件事情,或者(更糟糕的是)需要自己的模块,而这些模块本身不存在或具有语法错误。finnw的答案正是我所需要的。 - Thomas
4个回答

17

如果您需要区分缺失模块和语法错误,可以直接访问package.searchers中的搜索器函数。

这些函数将会:

  • 成功时返回一个加载器函数
  • 如果未找到模块,则返回一个字符串
  • 如果存在语法错误,则抛出一个错误

因此,您可以模仿require搜索模块的方式,依次调用每个搜索器函数,直到其中一个函数返回一个函数。与require不同的是,如果每个搜索器函数都返回一个字符串,我们无需抛出错误,即表示未找到模块。

function isModuleAvailable(name)
  if package.loaded[name] then
    return true
  else
    for _, searcher in ipairs(package.searchers or package.loaders) do
      local loader = searcher(name)
      if type(loader) == 'function' then
        package.preload[name] = loader
        return true
      end
    end
    return false
  end
end

使用 if isModuleAvailable("menu") then require("menu") end 进行测试的结果:如果 menu 包含语法错误,则会崩溃,如果缺少或正确,则成功。谢谢! - l0b0

9

看,我曾经遇到过“luafilesystem”模块的同样问题,我是这样解决的:

local haslfs,lfs = pcall(require,"lfs")
if haslfs then
  configLines["PROJECT_HOME"] = lfs.currentdir()
else
  configLines["PROJECT_HOME"] = prompt("Project path > ")
end

'lfs'在这里是模块句柄。使用pcall可知道模块是否真正加载,而不会传播错误。


6
我所做的是在pcall中包装require,以便加载模块并捕获无法加载的情况。 我使用的完全工作的函数可以从这里下载并安装缺少的模块: http://www.fhug.org.uk/wiki/doku.php?id=plugins:code_snippets:module_require_with_load
function loadrequire(module)
    local function requiref(module)
        require(module)
    end
    res = pcall(requiref,module)
    if not(res) then
        -- Do Stuff when no module
    end
end
loadrequire('menu')

1
看起来不错,我很快就会尝试。小提醒:是只有我觉得缩进不一致吗? - l0b0
2
为什么你可以直接使用res = pcall(require, module),却要创建一个本地内部函数呢? - Mike Corcoran
10b0 - 主要是因为我打了一些,然后粘贴了剩下的。Mike老实说我记不清了,我想我在一些插件中从几个地方调用了它。 - Jane T
这不会传播语法错误 - 只有一个布尔结果,没有指示出错原因 - 所以实际上并不是我需要的。 - l0b0
@DreamEater 这不是我所问的。这只是一个非常普遍的可读性因素。 - l0b0

0
我为可选导入创建了一个简单的 `want` 函数。
-- Optional require. Example:                                             
--     myMod, err = want'myMod'                                           
--     if not myMod then print(err) end                                   
local function want(name)                                                 
  local out; if xpcall(                         
      function()  out = require(name) end,           
      function(e) out = e end)
  then return out          -- success                                     
  else return nil, out end -- error                                       
end  

许可证:此代码属于公共领域。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接