lua类 - 无法设置属性和检索值

时间:2013-12-31 16:47:43

标签: class oop object lua

我正努力在lua中创建类。我已经编写了一些简单的代码来设置和获取字符串值,但我一直得到null。

这是我的班级定义:

appUser = {}
appUser_mt = { __index = appUser }

-- This function creates a new instance of appUser
function appUser:new()
    local new_inst = {}    -- the new instance
    setmetatable( new_inst, appUser_mt)-- all instances share the same metatable.
    return new_inst
end
-- Here are some functions (methods) for appUser:
function appUser:setLastName(lname)
    appUser._lname = lname
end

function appUser:setFirstName(fname)
    appUser._fname = fname
end

function appUser:getLastName()
    return appUser._lname
end

function appUser:getFirstName()
    return appUser._fname
end

return appUser -- do I need this???

尝试创建2个用户的测试代码如下所示:

require "user"
local a = appUser:new{setLastName="Doe"}
local b = appUser:new{setLastName="Doe-Doe"}
print(a.getLastName())
print(b.getLastName())

当我从命令行运行测试脚本时,这就是我得到的:

mydevbox:/usr/share/vsx/lib/testapp# lua testuser.lua
nil
nil
mydevbox:/usr/share/vsx/lib/testapp# 

我迄今为止所做的尝试:

  1. 我试过改变我调用方法的方式    打印(a.getLastName()) 至    打印(一个:getLastName())

  2. 我已经改变了变量定义:

    appUser._lname 至   _lname

  3. 这样我的代码就像这样:

    local _lname
    function appUser:setLastName(lname)
        _lname = lname
    end
    
    function appUser:getLastName()
        return _lname
    end
    

    我不确定我做错了什么。任何建议,将不胜感激。 谢谢。

    编辑1

    对代码进行了以下更改以测试Etan的答案和我的答案: 1.我已经将构造函数更改为接受参数,如我的答案中所述...... 我已经添加了对" self"的引用。在set / get函数的主体中。

    -- This function creates a new instance of appUser
    appUser = {}
    appUser_mt = { __index = appUser }
    
    function appUser:new(new_inst)
        new_inst = new_inst or {}    -- the new instance
        setmetatable( new_inst, appUser_mt)-- all instances share the same metatable.
        return new_inst
    end
    -- Here are some functions (methods) for appUser:
    function appUser:setLastName(lname)
        self._lname = lname
    end
    
    function appUser:setFirstName(fname)
        self._fname = fname
    end
    
    function appUser:getLastName()
        return self._lname
    end
    
    function appUser:getFirstName()
        return self._fname
    end
    

    测试脚本中的对象A和B仍然以nil失败,但是C有效,因为我没有像实例化a或b一样创建它。 (请参阅我的回答)

    修改2

    appUser = {}
    appUser_mt = { __index = appUser }
    
    function appUser:new()
        return setmetatable( {}, appUser_mt)-- all instances share the same metatable.   
    end
    
    local function validate_vmail(vmail_id)
        local success = true    
        if type(vmail_id) ~= 'string' then
            success = false
        end
    
        if not exists_in_database(vmail_id) then
            success = false
    
        end
        return success
    end 
    
    function appUser_mt.__index(t, k)
      if k == 'lastName' then
        return t._lastName
      end
      return rawget(t, k)
    end
    
    
    function appUser_mt.__newindex(t, k, v)
        local success = false
        if k == 'lastName' then
            k = '_lastName'
            v = v:gsub('^.', string.upper) -- Make sure the first letter is uppercase.
            success = true
        end
        if k == 'vmail_id' then     
            if validate_vmail(v) then
                v = v
                success = true
            else
                success = false
            end
        end
        if success then
            rawset(t, k, v)
        end 
    end    
    return appUser
    

    以下是实例化此类的客户端:

    local a = appUser:new()
    a.lastName = "doe"
    print(a.lastName)
    
    local b = appUser:new()
    b.lastName = "dylan"
    print(b.lastName)
    
    a.vmail_id = 1234
    print(a.vmail_id)
    

    代码似乎有效,但我想确保到目前为止我理解你的意见/答案。

3 个答案:

答案 0 :(得分:3)

模块

你没有在任何地方分配require "user"的结果,所以我假设你可能在某处隐藏了module个电话。如果您打算在不调用return appUser的情况下使用它,则需要module,例如:

-- mlib.lua
local M = {}
function M.add(a, b) return a + b end
return M

-- script.lua
local m = require'mlib'
print(m.add(2, 2))

构造

您可以简化构造函数。

function appUser.new()
  return setmetatable({}, appUser_mt)
end

我认为我理解你的意图使用下面的代码,但是如果没有一点调整它就不会按照你想要的方式工作。我会回到这个。

local a = appUser:new{setLastName="Doe"}
local b = appUser:new{setLastName="Doe-Doe"}

功能

请记住,只要您使用:定义函数,就会插入隐式self参数作为第一个参数。调用函数也是如此。

function t:f() end
function t.f(self) end
t.f = function(self) end

所有这些行都是等同的陈述。

t['f'](t)
t.f(t)
t:f()

Setters / Getters

Setter和getter根据需要不在任何地方,因为可能是其他语言。 Lua中没有表格的私有或公共接口的概念,因此如果你所做的只是分配和检索,那么你当前的设置可能会成为未来的维护责任。执行以下操作没有任何问题。

local class = {}
class.lastName = 'Doe'

事实上,有元方法设施,这样你就可以拦截某些键分配并对值执行操作,如果你真的想要setter但又希望它们融入与其他属性。我举个例子。

local mt = {}
function mt.__index(t, k)
  if k == 'lastName' then
    return t._lastName
  end
end

function mt.__newindex(t, k, v)
  if k == 'lastName' then
    k = '_lastName'
    v = v:gsub('^.', string.upper) -- Make sure the first letter is uppercase.
  end

  rawset(t, k, v)
end

local class = setmetatable({}, mt)
class.lastName = 'smith'
print(class.lastName) -- Smith

构造函数,pt。 2

为了解决这个问题,让我们看一下以下的陈述。

local a = appUser:new{setLastName="Doe"}

{setLastName = "Doe"}部分只是构建一个表格,其中包含一个名为setLastName的密钥(或属性),其值为"Doe",这两个字符串都是字符串。然后将其用作new的{​​{1}}函数的第二个参数。 appUser是第一个参数,用作前面提到的隐式appUser参数。请记住self

实际上根本没有必要。只需调用:作为没有appUser.new的函数就足够了,因为它不需要self。这就是全部。 new以任何方式知道使用参数setLastName调用"Doe"的方式还不是特别的,但我们可以这样做。


总而言之,这里有一个关于如何让你的构造函数以你想要的方式工作的想法。

function appUser.new(options)
  return setmetatable(options or {}, appUser_mt)
end

local a = appUser.new{_lname = 'Doe'}
local b = appUser.new{_lname = 'Doe-Doe'}

但是,如果你真的想在构造函数表本身中调用函数,那么这需要更多。

function appUser.new(options)
  local o = setmetatable({}, appUser_mt)

  for k, v in pairs(options)
    -- This will iterate through all the keys in options, using them as
    -- function names to call on the class with the values
    -- as the second argument.
    o[k](o, v)
  end

  return o
end

local a = appUser.new{setLastName = 'Doe'}
local b = appUser.new{setLastName = 'Doe-Doe'}

如果这还没有尽可能完整地回答你的问题,请告诉我。

答案 1 :(得分:1)

我实例化对象的方式失败了......

require "user"
local a = appUser:new{setLastName="Doe"}
local b = appUser:new{setLastName="Doe-Doe"}
print(a:getLastName())
print(b:getLastName())


local c = appUser:new()
c:setLastName("Dylan")
print(c:getLastName())

对象“c”的结果正确显示...

所以我猜问题是我的构造函数。我已经尝试将其更改为:

function appUser:new(new_inst)
    new_inst = new_inst or {}    -- the new instance
    setmetatable( new_inst, appUser_mt)-- all instances share the same metatable.
    return new_inst
end

但是这还没有固定对象a或b,但是我得到了适当的c

结果

答案 2 :(得分:0)

改变后的代码看起来应该可以正常工作,但是它和原版一样,存在的问题是它只支持所有appuser实例的单个lname或fname。您需要在定义的函数中使用自动self变量,以便它们正确地对传入的实例进行操作。

function appUser:setLastName(lname)
    self._lname = lname
end

function appUser:getLastName()
    return self._lname
end

此代码也没有按照您的想法执行(以及您希望它执行的操作)。

local a = appUser:new{setLastName="Doe"}
local b = appUser:new{setLastName="Doe-Doe"}

它不会在新的appUser实例上调用setLastName函数。您正在创建一个表({...}),为该表提供具有给定值setLastNameDoe的{​​{1}}密钥,然后将该表传递给appUser:new函数(然后提示忽略它,因为它不需要参数)。