lua - 一个默默失败的 Lua 迭代器?

标签 lua iterator assert

我对一个简单的迭代器有一个非常简单的问题。

假设我设计了一个函数,files() ,它遍历文件夹中的所有文件:

for file in files("/path/to/folder") do
  print(file)
end

现在,这看起来很完美,但这里有一个问题:如果文件夹不存在,或者我们没有读取权限怎么办?

我们将如何指出这样的错误?

一种解决方案是让 files()返回 nil, "no read permission"在这种情况下。然后我们就可以将调用封装到 files()assert() :
for file in assert(files("/path/to/folder")) do
  print(file)
end

这似乎解决了问题。但这迫使我们的用户始终使用 assert() .如果用户不关心错误怎么办?对于这类用户,我们希望我们的 files()表现得好像文件夹是空的。但是 Lua -- 万一files()表示错误——将尝试调用返回的 nil这将导致错误(“尝试调用 nil 值”)。

所以,

我们如何设计迭代器,files() ,这会同时满足关心错误的用户和不关心错误的用户吗?

如果不可能,您会建议什么替代方案?

最佳答案

第一:而不是返回 nil + 错误消息考虑在 files 中引发错误函数(使用 error )。这样你就不会忘记 assert调用,并且您不会遇到令人困惑的“尝试调用 nil 值”错误。

您可以将额外的 bool 参数传递给 files当你不想引发错误时——你应该返回一个空函数( function() end )而不是调用 error在这种情况下。

更通用的方法如下:

-- an iterator that immediately stops a for loop
local function dummy_iter() end

-- catch errors and skip for loop in that case
function iterpcall( g, ... )
  local ok, f, st, var = pcall( g, ... )
  if ok then
    return f, st, var
  else
    return dummy_iter
  end
end


for file in iterpcall( files, "/path/to/folder" ) do
  print( file )
  for line in iterpcall( io.lines, file ) do -- works for other iterators as well
    print( line )
  end
end
iterpcall的实现以上只处理迭代器生成器( filesio.lines )中引发的错误,而不是迭代器函数( f )本身。你必须包装 f在带有 pcall 的封口中要做到这一点。

关于lua - 一个默默失败的 Lua 迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24157253/

相关文章:

Python - 如何检查页面中不应存在的元素

java - 如何在android中使用断言?

c# - Verify() 和 Setup()...VerifyAll() 之间的最小起订量区别

c - 在c中嵌入lua代码

mysql - 如何从 tarantool 连接到 mysql?

c++ - 无法使用 std::string 作为键迭代 std::map

Java - 迭代列表中的每两个元素

serialization - 实际使用 Lua 协程/延续序列化来简化异步逻辑?

c++ - 如何从 Lua C API 中的函数获取多个返回值?

c++ - 在 C++ 映射上使用迭代器删除