类和方法 |
|
表可以作为关联数组使用。此功能允许我们将函数存储在类表中,即使用函数名映射到函数。
A = {} function A:add(x,y) return x+y end print( A:add(1,2) ) -- prints 3
A
的实例。如果我们想创建另一个实例,我们可以创建一个表 B
(例如,B={}
),并将所有方法从 A
复制到 B
中。
可以通过使用 Lua 的标签方法来创建类的多个实例。标签方法可以用来将来自类实例的函数请求重定向到类函数表。即,我们不再需要将所有类函数复制到类的每个实例中。例如:
-- settag() returns a table "{}" which has been tagged with a new tag value A = settag({},newtag()) -- use the index tag method to redirect a request for a function to the -- class function table settagmethod(tag(A),"index", function(t,f) return %A[f] end) function A:new(x,y) -- create an instance of class A local t = {x=x,y=y} settag(t,tag(A)) -- tag the new table to tell it what its class type is return t end function A:add() print (self.x+self.y) end function A:sum(a) assert(tag(self)==tag(a)) -- check they are same class print (self.x+a.x,self.y+a.y) end a = A:new(7,9) -- new instance of A a:add() b = A:new(2,4) -- new instance of A b:add() a:sum(b) -- "sum" of 2 instances
a:sub()
,会导致堆栈溢出,因为 Lua 会无限地查找无法识别的函数,然后是标签方法返回的 nil
。这可以通过使用 rawget(table,key)
从函数表中获取函数来解决。rawget()
在从表中获取键的值时不会调用任何标签方法。
settagmethod(tag(A),"index", function(t,f) return rawget(%A,f) end)
a.number = 123
a:number() -- try and call x
a.sum = 7 print( a.sum ) -- should this print <function> or 7 ? (it prints 7)
这个问题无法解决,因为调用请求不会告知标签方法需要哪种类型。我们可以选择一个优先级,例如,类实例值优先于函数表值。(这样做,我们可以支持函数重载。)
如果函数表优先,我们可以使用gettable 标签方法来首先检查函数表 A
中是否存在方法,例如:
settagmethod(tag(A), "gettable", function(t,k) if rawget(%A,k) then return rawget(%A,k) else return rawget(t,k) end end )
统一方法:这个问题在Sol(由 Edgar Toernig 开发的 Lua 分支)中通过引入统一方法得到了解决。在这里,一个函数/方法表与一个标签相关联。表查找发生时会发生什么取决于查找是如何调用的。即,a.foo
和 a:foo
有不同的含义。a.foo
查找名为 "foo" 的成员,而 a:foo
在标记的函数表中查找名为 "foo" 的方法。因此,您可以拥有两个成员,一个数据成员和一个函数成员,它们可以和谐共处,不会发生冲突。
t.foo
/ t:foo
问题(并允许存储任意数据)吗?它看起来像现有的 Lua 标签方法系统,或者修改后的?我不认为这仅仅是试图模拟 Python 的结果,这里存在冲突。即你的实现是有限制的。我认为元机制应该足够灵活以实现这样的功能。这是实现风格的问题吗?可以通过使用独立函数来避免这个问题,但我认为这不太整洁(在这个例子中,与 Python 不同)--NDT
operator[]
,要么通过专用的成员函数。字段访问和非字段访问之间没有歧义。Lua 的标签方法是有限制的。你无法区分用于访问字段的table[x]
和用于调用方法的table.x
/ table:x
。解决你的PythonDictionaries问题的简单方法是放弃使用原生表语法进行元素访问,而依赖于get
和set
等方法。这将使实现变得更加简单!--JohnBelmonte