Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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
Class lua类-can';t设置属性并检索值_Class_Oop_Object_Lua - Fatal编程技术网

Class lua类-can';t设置属性并检索值

Class lua类-can';t设置属性并检索值,class,oop,object,lua,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

我正在尝试用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())
local _lname
function appUser:setLastName(lname)
    _lname = lname
end

function appUser:getLastName()
    return _lname
end
当我从命令行运行测试脚本时,得到的结果如下:

mydevbox:/usr/share/vsx/lib/testapp# lua testuser.lua
nil
nil
mydevbox:/usr/share/vsx/lib/testapp# 
到目前为止我所尝试的:

  • 我试着改变调用方法的方式 打印(a.getLastName()) 到 打印(a:getLastName())

  • 我已将变量定义更改为:

    appUser.\u lname 到 _名字

  • 因此,我的代码如下所示:

    require "user"
    local a = appUser:new{setLastName="Doe"}
    local b = appUser:new{setLastName="Doe-Doe"}
    print(a.getLastName())
    print(b.getLastName())
    
    local _lname
    function appUser:setLastName(lname)
        _lname = lname
    end
    
    function appUser:getLastName()
        return _lname
    end
    
    我不确定我做错了什么。如有任何建议,将不胜感激。 谢谢

    编辑1

    对代码进行了以下更改,以测试Etan的答案和我的答案: 1.我已经更改了构造函数以接受我的答案中提到的参数。。。 2.我在set/get函数体中添加了对“self”的引用

    -- 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)
    

    代码似乎正在运行,但我想确保我理解您的评论/答案

    更改后的代码看起来应该可以正常工作,但与原始代码一样,它也存在一个问题,即对于所有appuser实例,它只支持一个lname或fname。您需要在定义的函数中使用automagic
    self
    变量,以便它们在传入的实例上正确操作

    function appUser:setLastName(lname)
        self._lname = lname
    end
    
    function appUser:getLastName()
        return self._lname
    end
    
    此外,这段代码并没有做您认为它做的事情(以及您希望它做的事情)


    它没有在新的appUser实例上调用setLastName函数。您正在创建一个表(
    {…}
    ),为该表提供一个带有给定值
    Doe
    Doe-Doe
    setLastName
    键,然后将该表传递给appUser:new函数(该函数随后会立即忽略它,因为它不带参数)。

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

    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

    模块的正确结果 您没有在任何地方分配
    require“user”
    的结果,因此我假设您可能有一个
    模块
    调用隐藏在某处。如果要在不调用
    模块的情况下使用appUser,则需要
    返回appUser
    ,例如:

    -- 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()
    
    二传手 setter和getter并不像在其他语言中那样需要。Lua中没有表的私有或公共接口的概念,因此如果您所做的只是分配和检索,那么您当前的设置将来可能会成为维护的负担。做以下事情没有错

    local class = {}
    class.lastName = 'Doe'
    
    事实上,如果您确实需要setter,但也希望它们与其他属性混合,则可以使用metamethod工具拦截某些键分配并对值执行操作。让我给你举个例子

    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”
    ,这两个键都是字符串。然后将其用作
    appUser
    new
    函数的第二个参数
    appUser
    是第一个参数,用作前面提到的隐式
    self
    参数。记住

    这其实根本没有必要。调用并定义
    appUser.new
    作为一个没有
    self
    的函数就足够了,因为它不需要一个。这就是全部
    new
    在某种程度上并不特别,因为它知道如何使用参数
    “Doe”
    调用
    setLastName
    ,但我们可以这样做


    综上所述,下面是一个如何让您的构造函数以您想要的方式工作的想法

    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'}
    

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

    我*相信“我不需要明确地引用self,因为我使用的是”:函数定义中的符号。我可能错了。。。我只是在学习。但是请看我刚刚发布的答案。函数创建的
    符号表示在函数参数中不需要
    self
    。这就是
    automagic
    部分。当您想要引用“调用”对象时,仍然需要函数体中的self。Etan,您能解释一下为什么我的“c”对象当前可以工作,而函数体中没有对self的引用吗?谢谢顺便说一下,你可以在我的帖子中查看编辑1。我尝试过你的建议,在主体中添加“self”,但它不起作用。你的c对象“起作用”,因为你正在调用setLastName函数。但是,在创建了a、b和c对象之后,就像您已经尝试调用
    print(a:get)一样