【问题标题】:Proper way to dynamically define LUA functions动态定义 LUA 函数的正确方法
【发布时间】:2019-12-06 21:20:23
【问题描述】:

过去一周我一直在玩 Lua,最终我编写了这种平静的代码。我发现您可以动态创建“继承”其他函数的新函数非常有用,因此程序员必须为其命名。我的问题是:

这叫什么?

有没有更好的方法来做到这一点? (循环数据结构并创建“改进”现有功能的附加功能)

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

【问题讨论】:

    标签: function lua metaprogramming


    【解决方案1】:

    我不认为你正在做的事情有什么特殊的名字,它只是动态创建函数。

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

    正确的for循环

    for i in pairs(D) do
    …
    end
    

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

    for i=1,100 do
    …
    end
    

    这里,pairs 返回一个迭代器函数,使用它的惯用方式是

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

    这里k 是一个键(如代码中的i),v 是一个值(当您需要访问对应的值)。

    无需动态创建函数!

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

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

    -- 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

    【讨论】:

    • 您给出了一个很好的例子,说明在循环中评估函数定义以产生不同的函数值。但是,它可能会掩盖这样一个事实,即除了执行流路径评估函数定义时,不会从任何函数定义创建函数值。换句话说,所有函数值都是“即时”创建的。
    【解决方案2】:

    作为一个整体,它没有名字,没有。有很多概念可以发挥作用:

    • First Class Functions 又名。可以分配给变量并像数字或字符串一样传递的函数。
    • 匿名函数又名。在没有明确给出名称的情况下创建的函数。 Lua 中的所有函数技术上都是匿名的,但通常它们在创建后立即分配给变量。
    • 元编程又名。编写程序编写程序。在任意数量的对象上创建函数(或方法)的循环非常简单,但我认为它是元编程。
    • Lua 表;这似乎很明显,但请考虑并非所有语言都具有这样的功能。 Javascript 有类似的 objects,但 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 2017-12-07
      • 2013-05-14
      • 1970-01-01
      • 2015-12-06
      • 2012-06-18
      • 1970-01-01
      相关资源
      最近更新 更多