如何保存布尔条件并稍后进行评估

我需要创建一个结构。这个结构必须包含一个“布尔条件”数组。类似于这样:

function ReturnStructure ()
    local structure = {
        {A < 10},
        {B == "smth"},
        {FunctionReturnsTrueOrFalse(params)},
        --...
    }
    return structure
end

structure = ReturnStructure()

print(structure[1][1]) -- 根据 A 的值打印 true 或 false

事实上,这些表格包含的是 true 或 false,而不是条件,因为当我们调用 ReturnStructure 函数并创建一个局部表格 structure 时,表格中的所有条件都会被执行。我想创建一个结构,其字段将包含不是布尔值,而是可以执行并获取布尔值的东西。我可以使用匿名函数来实现这一点:

function ReturnStructure ()
    local structure = {
        {function() return A < 10 end},
        {function() return B == "smth" end},
        {FunctionReturnsTrueOrFalse, params}, -- 我不在这一行中调用函数,只是将其地址和参数放入表格中。
        --...
    }
    return structure
end

structure = ReturnStructure()

print(structure[1][1]) -- 打印函数地址:0x109bdd0
print(structure[1][1]()) -- 打印 true 或 false。我在此字符串中执行条件。

所以,这是一个按照我想要的方式工作的代码,但它看起来非常丑陋。我想听听有关如何创建更简单,更美观的表格的想法,而不是在每个字段中打印 function() return ...。我认为我应该使用简单的面向对象编程(OOP)实现来将我的结构创建为对象,但我不知道如何做到这一点。我也很乐意得到一些方法、实现、文章等方面的参考,这些可以帮助我找到一些想法。

点赞
用户1847592
用户1847592
function ReturnStructure()
   local structure = {
      {'A < 10'},
      {'B == "smth"'},
      {FunctionReturnsTrueOrFalse, 'parameter'},
   }
   local function call_me(f, ...)
      return (type(f) == 'function' and f or assert((load or loadstring)('return '..f)))(...)
   end
   return setmetatable({}, {
      __index = function(t, k)
         if structure[k] then
            return call_me((table.unpack or unpack)(structure[k]))
         end
      end,
      __newindex = function(t, k, v) structure[k] = v end
   })
end

A = 2
B = "anything"
function FunctionReturnsTrueOrFalse(par)
   return #par > 5
end

structure = ReturnStructure()

print(structure[1])  -- true
print(structure[2])  -- false
print(structure[3])  -- true
structure[4] = {'1==0'}
print(structure[4])  -- false
function ReturnStructure ()
   local structure = {
     {'A < 10'},
     {'B == "smth"'},
     {FunctionReturnsTrueOrFalse, 'parameter'},
   }
   local function call_me(f, ...)
      return (type(f)=='function' and f or
         assert((load or loadstring)('return '..f)))(...)
   end
   return setmetatable({}, {
      __index =
         function(t,k)
            if structure[k] then
               return call_me((table.unpack or unpack)(structure[k]))
            end
         end,
      __newindex = function(t,k,v) structure[k] = v end
   })
end

A = 2
B = "anything"
function FunctionReturnsTrueOrFalse(par)
   return #par > 5
end

structure = ReturnStructure()

print(structure[1])  -- true
print(structure[2])  -- false
print(structure[3])  -- true
structure[4] = {'1==0'}
print(structure[4])  -- false
2014-03-24 07:34:56
用户501459
用户501459

我想听听如何创建一个更简单和更美观的表格的想法,而且不需要在每个字段中打印函数()返回...

没有。如果Lua有C#的lambda语法,你可以写成:

local structure = {
    () => A < 10,
    () => B == "smth",
    () => FunctionReturnsTrueOrFalse(params),

但是Lua喜欢保持简单,避免为该语言及其实现添加大小和复杂性,因此我们为一个函数类型提供一种语法。

您可以将它们存储为字符串,然后稍后编译和运行它们,但这是形式胜于功能。您不想不必要地调用编译器。

local structure = {
    'A < 10',
    'B == "smth"',
    'FunctionReturnsTrueOrFalse(params)',

因此,您的原始解决方案更好。我并不特别喜欢前两个项目推迟评估它们的参数的方式,而您的第三个示例在编译时评估参数。将FunctionReturnsTrueOrFalse处理相同会更加一致

local structure = {
    function() return A < 10 end,
    function() return B == "smth" end,
    function() return FunctionReturnsTrueOrFalse(param1) end,

这也意味着您不需要将它们放入表中。每个函数只是一个您调用的函数,这也简化了调用代码。

如果您真的想在编译时评估FunctionReturnsTrueOrFalse的参数,我会编写一个实用程序程序来从函数及其参数构建闭包:

local function bind(f, ...)
    local args = {...}
    return function() f(unpack(args)) end
end

然后使用它将函数绑定到它的参数:

local structure = {
    function() return A < 10 end,
    function() return B == "smth" end,
    bind(FunctionReturnsTrueOrFalse, param1, param2, param3),

然后,您表格中的所有内容都只是一个函数,因此无需特殊处理。

2014-03-24 18:35:42