Class lua类-can';t设置属性并检索值
我正在尝试用lua创建类。我已经编写了一些简单的代码来设置和获取字符串值,但结果总是返回null 下面是我的类定义: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
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#
到目前为止我所尝试的:
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)一样