Lua 中赋值覆盖的问题

我正在一个嵌入式环境/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 函数的调用。使用适当初始化的结构将 userdata 推送到栈中。必要时也会初始化硬件。返回一个新的 table。

第二行对参数对象进行赋值。我希望这会调用一个带有单个参数的 C 函数(分配的参数),以便将值存储到硬件寄存器中。

在第三行中,读取了参数。我再次需要调用向硬件寄存器获取参数值的 C 函数,并返回结果。

请注意,该参数的实际值可能在 Lua 的范围之外发生更改,因此在初始化期间仅读取一次该值是不正确的。必须每次调用 C 函数以获取实际值。类似地,对值的写入必须立即导致对硬件的写入。

如何实现?具体而言,我可以改变参数的元表来实现第 2 和第 3 行吗?(我知道如何实现第 1 行)。

此外,从构造函数返回一个 table 是否有必要?例如,我可以返回一个原始的 Lua 类型(如数字),它将像上面一样运作吗?

点赞
用户63791
用户63791

这不完全是你要求的,但很接近:

function createParameter(t)
  param = {}
  param.data = t
  backingTable = {}
  metatable = {}
  function metatable.__index(t, k)
    --如果你想要拦截值并将其传递给你的 C 函数,可以在此处进行拦截。
    return backingTable[k]
  end
  function metatable.__newindex(t, k, v)
    --如果你想要拦截值并将其传递给你的 C 函数,可以在此处进行拦截。
    backingTable[k] = v
  end
  setmetatable(param, metatable)
  return param
end

--------------------------------------------------------

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

my_param.value = 5

result = my_param.value + 3

print(result) --打印 8
print(my_param.data.name) --打印 hw_param1

你可能可以通过给全局表 _G 分配元表来实现一些诡计,但我认为这将有些棘手,可能会导致意想不到的结果。

编辑:

如果你真的讨厌必须在层次结构中使用,而且你真的想直接设置它,那么你可以通过设置全局表来实现。

globalMetatable = {}
globalParamNames = {}
globalParams = {}
function globalMetatable.__index(t, k)
  if globalParamNames[k] then
    --如果你想要拦截值并将其传递给你的 C 函数,可以在此处进行拦截。
    print("Read from param " .. k)
    return globalParams[k]
  else
    rawget(_G, k)
  end
end
function globalMetatable.__newindex(t, k, v)
  if globalParamNames[k] then
    --如果你想要拦截值并将其传递给你的 C 函数,可以在此处进行拦截。
    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) --打印 8
print(my_param) --打印 5
2018-07-26 22:20:56
用户10141568
用户10141568

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

第二行代码会完全改变该变量所持有的值。

但是,如果你设置参数对象中的一个字段,比如 my_param.x = n,这将会调用 __newindex 元方法;你可以重写这个元方法来按照你需要的方式进行操作。在你的情况下,你将需要使用一个 C 函数调用来设置参数的字段并更新它。

关于第三行代码,同样的原理依旧适用,只需要使用 __add 元方法,然后在 __add 被调用时对对象进行操作即可。

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

2018-07-26 22:32:57