简体   繁体   English

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

[英]How to use table.concat in Lua tables containing functions

I'm using Lua tables to store data to create web pages. 我正在使用Lua表存储数据来创建网页。 The body content is stored in a single table, there is some static text and some generated by Lua functions. 正文内容存储在单个表中,有一些静态文本,一些由Lua函数生成。

Web.HTML={
"<h1>Hello World</h1><br>",
"<br><h2>Current Directory</h2><br>",
io.popen("cd"):read('*l'),
"<br><h2>Current Lua Interpreter</h2><br>",
arg[-1] or arg[0],
"<br><h2>Current Package Path</h2><br>",
package.path:gsub(";",";<br>\n"),
"<br><h2>Current Package CPath</h2><br>",
package.cpath:gsub(";",";<br>\n"),
"<br><h2>Current Environment Table:</h2><br>",
io.popen("set"):read('*a'):gsub("\n","<br>\n").." ",
"<br><h2>Current Date:</h2><br>",
os.date(),
"<br><h2>Math calculation</h2><br>",
math.pi/180
}

This table is then "printed" using table.concat function, adding some newlines to aid readability: 然后使用table.concat函数“打印”该表,添加一些新行以帮助提高可读性:

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

The example above works as expected in Lua 5.1 or equivalent and the server successfully passes this as part of my web page. 上面的示例在Lua 5.1或同等版本中按预期工作,服务器成功将其作为我的网页的一部分传递。

I would like to to place arbitrary Lua code in my HTML table which returns a string to be concatenated, but I can't find the correct syntax. 我想在我的HTML表中放置任意Lua代码,它返回一个要连接的字符串,但是我找不到正确的语法。 The concat function complains invalid value (function) at index in table for 'concat' . concat函数在表中为'concat'的索引处抱怨无效值(函数)

I have tried: 我试过了:

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

and

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

A more useful example would be to list all the tables in the Lua global environment: 一个更有用的例子是列出Lua全局环境中的所有表:

Web.HTML = {
    "<br><h2>Current Lua Libraries</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
    ,
    "Success!"
}

I have also tried using loadstring( code ;return text )() as an entry in my table without success. 我也尝试使用loadstring( 代码 ;返回文本)()作为我的表中的条目,但没有成功。 Any pointers welcome. 欢迎任何指示。

Thanks in advance. 提前致谢。

Gavin 加文

function returns, obviously, a function. function显然是一个函数返回。 Just call it immediately with () . 只需使用()立即调用它。 Also don't forget to change print to return - your function needs to return value for table, not to print it out! 另外不要忘记更改print return - 您的功能需要返回表的值,而不是打印出来!

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

print(table.concat(Web.HTML,"<br>\n"))
-- Classic text example:<br>
-- Hello World

table.concat will not automagically execute code that it encounters. table.concat不会自动执行它遇到的代码。 It concatenates a list of strings (or numbers); 它连接一个字符串(或数字)列表; that's its job. 这是它的工作。 If you pass it something that isn't a list of strings, then you have done something wrong. 如果你传递的东西不是字符串列表,那么你做错了。

If you have a list of strings+functions-that-return-strings, then you need to transform this into a list of strings yourself . 如果你有一个字符串+的功能,也就是说,返回的字符串列表,那么你就需要转换成字符串自己的名单这一点。 This is easily done: 这很容易做到:

local list = --However you generate it.
for i, val in ipairs(list) do
  if(type(val) == "function") then
    list[i] = val() --call function
  end
end

Then you can concatenate list with table.concat . 然后你可以用table.concat连接list If you want to create a copy of the table, instead of overwriting the existing one, then that's easily done as well. 如果要创建表的副本,而不是覆盖现有表,那么也可以轻松完成。

local list = --However you generate it.
local copy = {}
for i, val in ipairs(list) do
  if(type(val) == "function") then
    copy[i] = val() --call function
  else
    copy[i] = val
  end
end

table.concat concatenates the elements of a table to a string. table.concat将表的元素连接到字符串。 Therefor it is mandatory that every element in the table can be converted to a string. 因此,必须将表中的每个元素转换为字符串。

In all your attempts: 在你所有的尝试中:

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

Web.HTML[2] is a function which cannot be converted to a string. Web.HTML[2]是一个无法转换为字符串的函数。

You could replace your functions by strings or their return values in this case by simply defining them outside your list and then calling them in your table constructor or calling them right away with the function definitin in parentheses, or you could overload table.concat to your needs. 您可以通过字符串或其返回值替换您的函数,在这种情况下,只需在列表外定义它们然后在表构造函数中调用它们或立即使用括号中的函数definitin调用它们,或者您可以将table.concat重载到您的需要。 Although I would rather implement a new concat function instead of overwriting the standard one to avoid confusion. 虽然我宁愿实现新的concat函数而不是覆盖标准函数以避免混淆。

Unfortunately, standard function table.concat() works only with strings and numbers. 不幸的是,标准函数table.concat()仅适用于字符串和数字。

You may write your own more versatile table.concat : 你可以编写自己更多功能的table.concat

do
   local orig_table_concat = table.concat

   -- Define new function "table.concat" which overrides standard one
   function table.concat(list, sep, i, j, ...)
      -- Usual parameters are followed by a list of value converters
      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' is always the final converter
      end
      return orig_table_concat(t, sep, i, j)
   end
end

Examples of usage: 用法示例:

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

-- without converters
print(table.concat(Web.HTML, "<br>\n"))
--> Classic text example:<br>
--> function: 0x9ad1398

-- with a converter
print(table.concat(
   -- usual parameters for table.concat:
   Web.HTML, "<br>\n",
   -- additional parameters (converters):
   function(x)
      if type(x) == 'function' then
         return x()
      else
         return x
      end
   end
))
--> Classic text example:<br>
--> Hello World

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM