【问题标题】:Overriding assignment of value in Lua覆盖 Lua 中的赋值
【发布时间】:2018-07-26 22:02:37
【问题描述】:

我在 C 应用程序(嵌入式环境/MCU)中使用 Lua v5.2.2。

我需要在 Lua 中公开一些“参数”,对于读取和写入,您需要直接访问硬件(因此需要 C 调用)。但是,我正在寻找其他方法来实现这一点,而不是使用普通的旧 getter 和 setter。

我主要在探索 Lua 的元编程能力,但我也相信我可以为用户创建一个更简单的界面。

我想要实现的是如下行为:

my_param = createParameter{name="hw_param1", type="number", min=0, max=100}

my_param = 5

result = my_param + 3

在第一行创建了一个新参数。这是对 C 函数的调用。使用正确初始化的结构将用户数据推送到堆栈。硬件也会根据需要进行初始化。返回一个新表。

在第二行,对参数对象进行了赋值。我希望它使用单个参数(赋值参数)调用 C 函数,因此可以将值存储到硬件寄存器中。

在第三行读取参数。我再次需要调用一个 C 函数,该函数将从硬件寄存器中获取参数的值,然后返回结果。

注意这个参数的实际值可能会在Lua范围之外发生变化,所以在初始化时读取一次值是不正确的。每次都必须调用 C 函数才能获取实际值。同样,写入值必须立即写入硬件。

我怎样才能做到这一点?具体来说,我可以改变参数的元表来实现第 2 行和第 3 行吗? (我知道如何实现第 1 行)。

还有必要从构造函数返回一个表吗?例如,我可以返回一个与上述行为类似的原始 Lua 类型(例如数字)吗?

【问题讨论】:

    标签: c lua


    【解决方案1】:

    这不是您想要的,但很接近:

    function createParameter(t)
      param = {}
      param.data = t
      backingTable = {}
      metatable = {}
      function metatable.__index(t, k)
        -- You can intercept the value here if you 
        -- want and pass it on to your C fuction.
        return backingTable[k]
      end
      function metatable.__newindex(t, k, v)
        -- You can intercept the value here if you 
        -- want and pass it on to your C fuction.
        backingTable[k] = v
      end
      setmetatable(param, metatable)
      return param
    end
    
    --------------------------------------------------------
    
    my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
    
    my_param.value = 5
    
    result = my_param.value + 3
    
    print(result) -- prints 8
    print(my_param.data.name) -- prints hw_param1
    

    您可以通过将元表分配给全局表 _G 来做一些棘手的事情,但我认为正确设置会有点棘手,并且可能导致意外结果。

    编辑:

    如果您真的讨厌必须有一个间接级别,并且您真的希望能够直接设置它,那么您可以通过设置全局表来做到这一点。

    globalMetatable = {}
    globalParamNames = {}
    globalParams = {}
    function globalMetatable.__index(t, k)
      if globalParamNames[k] then
        -- You can intercept the value here if you 
        -- want and pass it on to your C fuction.
        print("Read from param " .. k)
        return globalParams[k]
      else 
        rawget(_G, k)
      end
    end
    function globalMetatable.__newindex(t, k, v)
      if globalParamNames[k] then
        -- You can intercept the value here if you 
        -- want and pass it on to your C fuction.
        print("Wrote to param " .. k)
        globalParams[k] = v
      else
        rawset(_G, k, v)
      end
    end
    setmetatable(_G, globalMetatable)
    
    function createParameter(t)
      globalParamNames[t.varname] = true
    end
    
    --------------------------------------------------------
    
    createParameter{varname="my_param", name="hw_param1", type="number", min=0, max=100}
    
    my_param = 5
    
    result = my_param + 3
    
    print(result) -- prints 8
    print(my_param) -- prints 5
    

    【讨论】:

      【解决方案2】:

      是的,您可以修改元表元方法。

      第 2 行将完全改变它所持有的变量值。

      但是,如果您要在参数对象中设置一个字段,例如:my_param.x = n,则将调用 __newindex 元方法;您可以覆盖元方法以按照您的意愿行事。在您的情况下,您可以设置参数的字段并使用 C 函数调用对其进行更新。

      关于第 3 行,同样的原则适用,但这次您只需使用 __add 元方法,并在调用 __add 时操作对象。

      http://lua-users.org/wiki/MetamethodsTutorial

      【讨论】:

      • 不正是我所要求的。本质上,我希望 my_param = n 调用一个函数而不是进行赋值。这可能吗?
      • 有可能,但有点奇怪。请参阅下面对我的答案的修改。
      猜你喜欢
      • 2016-12-23
      • 2021-03-19
      • 2014-09-27
      • 1970-01-01
      • 2010-10-13
      • 2013-03-20
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      相关资源
      最近更新 更多