如何在Lua表中包含函数并使用table.concat

我使用Lua表来存储数据以创建网页。正文内容存储在一个单一的表中,其中包含一些静态文本和一些由Lua函数生成的内容。

Web.HTML={
"<h1>你好,世界</h1><br>",
"<br><h2>当前目录</h2><br>",
io.popen("cd"):read('*l'),
"<br><h2>当前Lua解释器</h2><br>",
arg[-1] or arg[0],
"<br><h2>当前包路径</h2><br>",
package.path:gsub(";",";<br>\n"),
"<br><h2>当前包C路径</h2><br>",
package.cpath:gsub(";",";<br>\n"),
"<br><h2>当前环境表:</h2><br>",
io.popen("set"):read('*a'):gsub("\n","<br>\n").." ",
"<br><h2>当前日期:</h2><br>",
os.date(),
"<br><h2>数学计算</h2><br>",
math.pi/180
}

然后使用table.concat函数"打印"此表,添加一些换行符以帮助阅读:

print(table.concat(Web.HTML,"<br>\n"))

上面的示例在Lua 5.1或等效版本中按预期工作,并且服务器成功地将其作为我的网页的一部分传递。

我想在我的HTML表中放置任意Lua代码,该代码返回一个要连接的字符串,但我无法找到正确的语法。concat函数抱怨在表中的索引处的无效值(函数)。

我已经尝试过:

Web.HTML = {
"经典文本示例:",
function() print "你好,世界"; end,
}

Web.HTML = {
"经典文本示例:",
function() return "你好,世界"; end,
}

一个更有用的例子是列出Lua全局环境中的所有表:

Web.HTML = {
    "<br><h2>当前Lua库</h2><br>",
    function()
        local text = ''
        for i,v in pairs(_G) do
            if type(v)=="table" then
               text = text..i.."<br>\n"
            end
        end
        return text
    end
    ,
    "成功!"
}

我还尝试在表中使用loadstring( code ;return text )(),但没有成功。任何提示都欢迎。

提前致谢。

Gavin

点赞
用户734069
用户734069

table.concat 不会自动执行它遇到的代码。它将连接一个字符串(或数字)列表;这是它的工作。如果你传递给它一些不是字符串列表的东西,那么你是做错了什么。

如果你有一个字符串+返回字符串函数列表,那么你需要自己将它转换成一个字符串列表。这很容易做到:

local list = --不管你如何生成它。
for i, val in ipairs(list) do
  if(type(val) == "function") then
    list[i] = val() --调用函数
  end
end

然后你就可以使用 table.concat 连接 list。如果你想创建一个表的副本,而不是覆盖原有的表,那么这也很容易做到。

local list = --不管你如何生成它。
local copy = {}
for i, val in ipairs(list) do
  if(type(val) == "function") then
    copy[i] = val() --调用函数
  else
    copy[i] = val
  end
end
2016-03-21 14:32:44
用户936986
用户936986

function 返回的显然是一个函数。只需立即使用 () 调用它。同时也别忘了把 print 改为 return - 你的函数需要返回值给表格,而不是将其打印出来!

Web.HTML = {
    "经典文本示例:",
    (function() return "Hello World"; end)(),
}

return (table.concat(Web.HTML,"<br>\n"))
-- 经典文本示例:<br>
-- Hello World
2016-03-21 15:05:59
用户2858170
用户2858170

table.concat 函数将表的元素连接成一个字符串。因此,每个表中的元素都必须能够转换为字符串。

在你的所有尝试中:

Web.HTML = {
"经典文本示例:",
function() print "Hello World"; end,
}

Web.HTML[2] 是一个函数,无法转换为字符串。

在这种情况下,你可以将函数替换为字符串或使用它们的返回值,只需要将它们定义在列表外部,然后在表构造函数中调用它们,或者用带有函数定义的括号直接调用它们,或者你可以根据自己的需要重载 table.concat 函数。虽然我宁愿实现一个新的连接函数,而不是覆盖标准函数,以避免混淆。

2016-03-21 15:10:13
用户1847592
用户1847592

很不幸,标准函数 table.concat() 只适用于字符串和数字。

你可以编写更加通用的 table.concat 函数:

do
   local orig_table_concat = table.concat

   -- 定义一个新函数 "table.concat",覆盖标准的函数
   function table.concat(list, sep, i, j, ...)
      -- 常规参数后面是一个值转换器列表
      local first_conv_idx, converters, t = 4, {sep, i, j, ...}, {}
      local conv_types = {
         ['function'] = function(cnv, val) return cnv(val)        end,
         table        = function(cnv, val) return cnv[val] or val end
      }
      if conv_types[type(sep)]   then first_conv_idx, sep, i, j = 1
      elseif conv_types[type(i)] then first_conv_idx,      i, j = 2
      elseif conv_types[type(j)] then first_conv_idx,         j = 3
      end
      sep, i, j = sep or '', i or 1, j or #list
      for k = i, j do
         local v, idx = list[k], first_conv_idx
         while conv_types[type(converters[idx])] do
            v = conv_types[type(converters[idx])](converters[idx], v)
            idx = idx + 1
         end
         t[k] = tostring(v) -- 'tostring' 总是最终的转换器
      end
      return orig_table_concat(t, sep, i, j)
   end
end

使用示例:

Web = {}
Web.HTML = {
   "Classic text example:",
   function() return "Hello World"; end,
}

-- 没有转换器
print(table.concat(Web.HTML, "<br>\n"))
--> Classic text example:<br>
--> function: 0x9ad1398

-- 使用一个转换器
print(table.concat(
   -- 常规参数作为 table.concat 的参数:
   Web.HTML, "<br>\n",
   -- 额外的参数 (转换器):
   function(x)
      if type(x) == 'function' then
         return x()
      else
         return x
      end
   end
))
--> Classic text example:<br>
--> Hello World
2016-03-21 16:25:07