Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lua5.1中的_调用元方法实际上是如何工作的?_Lua_Call - Fatal编程技术网

Lua5.1中的_调用元方法实际上是如何工作的?

Lua5.1中的_调用元方法实际上是如何工作的?,lua,call,Lua,Call,作为练习,我正在尝试在Lua中实现一个集合。具体地说,我希望采用Pil2 11.5的简单集实现,并将其扩展到包括插入值、删除值等功能 现在最明显的方法是: 正如预期的那样,我把数字1到6打印出来了。但是那些对Set.insert(s,value)的调用真的很难看。我更希望能够调用类似于ts:insert(value)的东西 我第一次尝试解决这个问题的方法是这样的: Set = {} function Set.new(l) local s = { insert = func

作为练习,我正在尝试在Lua中实现一个集合。具体地说,我希望采用Pil2 11.5的简单集实现,并将其扩展到包括插入值、删除值等功能

现在最明显的方法是:

正如预期的那样,我把数字1到6打印出来了。但是那些对
Set.insert(s,value)
的调用真的很难看。我更希望能够调用类似于
ts:insert(value)
的东西

我第一次尝试解决这个问题的方法是这样的:

Set = {}
function Set.new(l)
    local s = {
        insert = function(t, v)
            t[v] = true
        end
    }
    for _, v in ipairs(l) do
        s[v] = true
    end
    return s
end

ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)

for k in pairs(ts) do
    print(k)
end
在您看到结果之前,这基本上是正常的:

1
2
3
4
5
6
insert
很明显,正在显示作为集合表成员的insert函数。这不仅比原来的
Set.insert(s,v)
问题更难看,而且还容易出现一些严重的问题(比如如果“insert”是有人试图输入的有效密钥会发生什么情况?)。是时候再读书了。如果我试试这个会怎么样

Set = {}
function Set.new(l)
    local s = {}
    setmetatable(s, {__call = Set.call})
    for _, v in ipairs(l) do
        s[v] = true
    end
    return s
end
function Set.call(f)
    return Set[f]
end
function Set.insert(t, v)
    t[v] = true
end

ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)

for k in pairs(ts) do
    print(k)
end
现在我阅读这段代码的方式是:

  • 当我调用
    ts:insert(5)
    时,
    insert
    不存在以被调用的事实意味着
    ts
    元表将被搜索
    “\u调用”
  • ts
    元表的
    “\u call”
    键返回
    Set.call
  • 现在,调用
    Set.call
    时使用的名称是
    insert
    ,这会导致它返回
    Set.insert
    函数
  • Set.insert(ts,5)
    被调用
真正发生的是:

lua: xasm.lua:26: attempt to call method 'insert' (a nil value)
stack traceback:
        xasm.lua:26: in main chunk
        [C]: ?

在这一点上,我被难住了。我完全不知道从这里到哪里去。我在这段代码上进行了一个小时的黑客攻击,不同程度的变异越来越令人绝望,但最终的结果是我没有任何有效的东西。在这一点上,我忽略了什么显而易见的事情?

我修改了您的第一个版本,这个版本将提供我认为您需要的功能

Set = {}
function Set.new(l)
    local s = {}
    setmetatable(s, {__index=Set})
    for _, v in ipairs(l) do
        s[v] = true
    end
    return s
end
function Set.call(f)
    return Set[f]
end
function Set.insert(t, v)
    t[v] = true
end

ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)

for k in pairs(ts) do
    print(k)
end
Set = {}
Set.__index = Set 

function Set:new(collection)
  local o = {}
  for _, v in ipairs(collection) do
    o[v] = true
  end 
  setmetatable(o, self)
  return o
end

function Set:insert(v)
  self[v] = true
end

set = Set:new({1,2,3,4,5})
print(set[1]) --> true
print(set[10]) --> nil
set:insert(10)
print(set[10]) --> true
你说:

现在我阅读这段代码的方式是:

  • 当我调用ts:insert(5)时,事实上insert并不 要调用的exist表示ts元表正在运行 要搜索“\uuu call”
  • ts元表的“\uuuu call”键返回Set.call
  • 现在调用Set.call时使用名称insert,该名称导致 它可以返回Set.insert函数
  • 调用Set.insert(ts,5)
不,情况是这样的:

Set = {}
function Set.new(l)
    local s = {}
    for _, v in ipairs(l) do
        s[v] = true
    end
    return s
end
function Set.insert(s, v)
    s[v] = true
end

ts = Set.new {1,2,3,4,5}
Set.insert(ts, 5)
Set.insert(ts, 6)

for k in pairs(ts) do
    print(k)
end
  • 如果在
    ts
    对象中未直接找到
    insert
    ,Lua将在其元表中查找
    \uu索引。
    • 如果它在那里并且是一个表,Lua将在那里搜索
      insert
    • 如果它在那里并且是一个函数,它将使用原始表(
      ts
      在本例中)和正在搜索的键(
      insert
      )调用它
    • 如果它不在那里,则视为
      nil
出现的错误是因为在元表中没有设置
\u索引
,因此实际上是在调用
nil

这可以通过将
\u index
指向某个表来解决,即
Set
,如果要将方法存储在该表中

对于
\u调用
,它用于将对象作为函数调用时。即:

Set = {}
function Set.new(l)
    local s = {}
    setmetatable(s, {__index=Set, __call=Set.call})
    for _, v in ipairs(l) do
        s[v] = true
    end
    return s
end
function Set.call(s, f)
    -- Calls a function for every element in the set
    for k in pairs(s) do
        f(k)
    end
end
function Set.insert(t, v)
    t[v] = true
end

ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)

ts(print) -- Calls getmetatable(ts).__call(ts, print),
          -- which means Set.call(ts, print)

-- The way __call and __index are set,
-- this is equivalent to the line above
ts:call(print)
现在我阅读这段代码的方式是:

  • 当我调用ts:insert(5)时,insert不存在以被调用这一事实意味着将在ts元表中搜索“\u call”
这是你的问题。调用表本身(即作为函数)时,将参考
\u调用
元方法:

Lua中的面向对象冒号调用如下:

ts:insert(5)
只是语法上的糖分

ts.insert(ts,5)
ts["insert"](ts,5)
这本身就是语法上的糖

ts.insert(ts,5)
ts["insert"](ts,5)
因此,对
ts
执行的操作不是调用,而是索引
ts[“insert”]
的结果就是所调用的内容),它由
\u index
元方法控制

\uuuu index
元方法可以是一个简单情况下的表,您希望索引“回退”到另一个表(请注意,被索引的是元表中的uuu索引键的值,而不是元表本身):

\uuu index
元方法作为一个函数,其工作原理与Set.call预期的签名类似,只是它在键之前传递要索引的表:

local ff = {}
local mt = {}

function ff.example(...)
  print("Example called!",...)
end

function mt.__index(s,k)
  print("Indexing table named:", s.name)
  return ff[k]
end

local ts = {name = "Bob"}
setmetatable(ts, mt)
ts.example(5) --> prints "Indexing table named:" and "Bob",
              --> then on the next line "Example called!" and 5

有关元表的更多信息,请参阅。

+1以实际解释原始代码的错误。顺便说一句,因为我将
call(s,f)
函数放在
Set
——即
getmetatable(ts)。\uu index
——您还可以编写
ts:call(打印)
。这基本上是Zecc的答案,带有更多中间示例代码。很可能是,但我被说服了。:)美好的谢谢你的指点和非常详细的回答。完整的答案,但对于像我这样的新手来说很容易理解。杰出的美丽的解释;我想知道如何实现JavaScript风格的行为,其中函数是哈希表的一个子类型(因此可以使用通常的
table.key
语法访问属性)。(更广泛的背景是,我正在尝试创建类,我喜欢JavaScript的
Car.staticProperty
表示法,但更喜欢Python风格的
Car()
构造函数表示法,而不使用
new
关键字。)这个答案告诉我,我可以简单地使用一个表并给它一个
\u调用
元方法来实现同样的效果!谢谢只想说我绝对爱你的用户名