lua类构造函数中的本地对象?

问题描述 投票:0回答:1

我是 Lua“类”(元表)的新手,我有疑问。

在我编写的以下构造函数代码中,我将变量

obj
声明为
local
。但在网络上的大多数示例中,该变量只是在没有
local
声明的情况下被分配。所以根据我的理解,它变成了一个全局变量(根据我的理解,效率不高)。但这有理由吗?

A = {}  
A.__index = A

function A:new(obj_init)      
  local obj = obj_init or {val = 0}     
  setmetatable(obj, A)      
  return obj  
end

我还注意到类的成员可以直接访问,甚至可以从另一个 Lua 模块访问:

x = A:new{val = 2}
print(x.val)

但是有没有办法让

val
成为私人会员呢?也许还可以使用
local

class lua
1个回答
2
投票

首先,让我们看看您找到的这些示例可能是什么样子。

参数:隐式局部变量

function A:new(obj)
  obj = obj or {val = 0}
  ...
end

在此代码片段中,

obj
是一个local变量。这是因为Lua中所有函数参数都是局部变量。我们可以将函数重写如下以突出这一点:

function A:new(...)
  local obj = ...
  obj = obj or {val = 0}
end

我想这就是你所看到的,例如在 PIL 中。您可能将参数重命名为

obj_init
,丢失了
obj
的隐式本地声明。

全局分配

如果您碰巧消耗了特别糟糕的资源,您可能会看到以下内容:

function A:new(obj_init)
  obj = obj_init or {val = 0}
  ...
end

在这个片段中,

obj
确实是一个全局变量。 由于多种原因,这非常糟糕:

  • 效率:你是对的 - 除了病理情况外,全局变量总是比局部变量慢,因为全局变量是(哈希部分)
    _G
    表中的条目,而局部变量存储在 Lua VM 的快速寄存器中。
  • 代码质量:全局污染:这个构造函数现在有一个副作用:它修改了全局变量
    obj
    ,并期望它在执行过程中不被修改。这可能会导致该函数覆盖全局变量
    obj
    ,更糟糕的是,您现在可能无法从构造函数中的协程中产生收益,因为您依赖于可能无法更改的全局状态。

私人会员

在Lua中实现私有表字段的典型方法是按照约定:您可以在字段名称前添加下划线,以表明这些字段不能从外部修改。当然,程序员可以自由地规避这一点。

否则,“私有”变量的概念与 Lua 脚本语言的本质不太吻合;你可以使用元表将成熟的OOP硬塞到Lua上,但这既不惯用,也不高效。

升值

在 Lua 中实现私有成员的最惯用的方法是让它们成为闭包的上值(“访问器”):

A = {}  
A.__index = A

function A:new(obj_init)
  local obj = {} -- empty object: only member is private
  local val = obj_init.val
  -- note: this does not need `self`, thus no `:` is used;
  -- for setters you might want to discard `self` for consistency
  function obj.getVal()
      return val
  end
  setmetatable(obj, A)      
  return obj  
end

x = A:new{val = 2}
print(x.getVal())
-- val can not be set from outside (excepting the debug library);
-- it is "private" and only accessible through the getter method

缺点是访问私有成员的所有函数都必须在每次创建对象时实例化。

请注意,即使上值也不是完全“私有”的,因为它们可以通过调试库访问。

debug
库解决方法

debug
库允许您检查堆栈。这使您可以知道哪个方法触发了您的
__index
元方法。因此,您可以向不同的调用者返回不同的值。这对于展示 Lua 元编程功能的概念验证来说可能很好,但在实践中不应该这样做,因为它非常低效和 hacky。

© www.soinside.com 2019 - 2024. All rights reserved.