动态定义 LUA 函数的正确方法

Proper way to dynamically define LUA functions

过去一周我一直在玩 Lua,最后写出了这段平静的代码。我发现动态创建 "inherit" 其他函数的新函数非常有用,因此程序员必须为其命名。我的问题是:

这个叫什么?

有更好的方法吗? (循环数据结构并创建 "improve" 现有函数的附加函数)

D = {
  name = {
    value = nil,
    offset = 0,
    update = function (self)
      self.value = "Berlin"
    end,
  },
}

--Dynamic function definition
for i in pairs(D) do
  D[i].upAndWrite = function(self)
    self:update()
    print("upAndWrite was here")
  end
end

print(D.name.value)
D.name:upAndWrite()
print(D.name.value)

结果:

nil
upAndWrite was here
Berlin

我不认为你正在做的事情有专门的名字,它只是即时创建的函数。

关于您的代码的注释很少:

正确的for循环

for i in pairs(D) do
…
end

在编程中,变量i一般用于计数器循环,如

for i=1,100 do
…
end

这里,pairs returns 一个迭代器函数,惯用的用法是

for k,v in pairs(D) do
…
end

这里 k 是一个键(就像代码中的 i 一样),v 是一个值(使用它而不是像 [=20= 那样索引 table ] 或 D[i] 在您的代码中,当您需要访问相应的值时)。

无需即时创建函数!

另一件重要的事情是在每次循环迭代时创建新函数。虽然此功能非常强大,但您根本没有使用它,因为您没有使用上值存储任何内容,并且仅通过参数访问数据。

更好的方法是创建一次函数并将其分配给每个字段:

-- Define D here

do
    local function upAndWrite(self)
        self:update()
        print("upAndWrite was here")
    end

    for k,v in pairs(D) do
        v.upAndWrite = upAndWrite -- Use our function
    end
end

-- Perform tests here

即时函数创建允许什么?

如上所述,您可以在某些情况下利用这种非常强大的闭包机制。这是一个简单的例子:

local t = {}

for i = 1, 100 do
    -- Create function to print our value
    t[i] = function() print(i) end

    -- Create function to increment value by one
    t[-i] = function() i=i+1 end
end

t[1]()   -- Prints 1
t[20]()  -- Prints 20
t[-20]() -- Increment upvalue by one
t[20]()  -- Now it is 21!

此示例演示了上值的一种可能用法以及许多函数可以共享它们的事实。这在多种情况下都非常有用,而且 upvalues 不能通过辅助代码(不使用 debug 库)更改并且通常可以信任.

希望我的回答能涵盖您想知道的内容。

注意:此外,这种语言称为 Lua, not LUA

作为一个整体,它没有名字,没有。这里有很多概念:

  • 第一个 Class 函数 又名。可以分配给变量并像数字或字符串一样传递的函数。
  • 匿名函数又名。创建的函数没有明确地给它一个名字。 Lua 中的所有函数都是 技术上 匿名的,但通常它们在创建后立即被分配到一个变量中。
  • 元编程又名。编写编写程序的程序。在任意数量的对象上创建函数(或方法)的循环非常简单,但我认为它是元编程。
  • Lua 表格;这似乎很明显,但请考虑并非所有语言都具有这样的功能。 Javascript 有 个相似的对象 ,但是 Ruby 没有类似的特征。

如果您要使用 pairs,您不妨同时使用这两个变量。

for key, object in pairs(D) do
  function object:upAndWrite(self)
    self:update()
    print("upAndWrite was here")
  end
end

虽然这会创建很多闭包,这意味着垃圾收集器需要做更多的工作,更多的内存使用和更慢的执行速度。

for key, object in pairs(D) do
  print(object.upAndWrite) -- All the functions are different
end

这是一个很好的第一阶段,但在稍微重构之后你可以得到这个:

do
   local method = function(self) -- Create only one closure
      self:update()
      print("upAndWrite was here")
   end

   for key, object in pairs(D) do
      object.upAndWrite = method -- Use single closure many times
   end
end

现在只有一个闭包在所有表之间共享。

for key, object in pairs(D) do
  print(object.upAndWrite) -- All the functions are the same
end