我正努力在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#
我迄今为止所做的尝试:
我试过改变我调用方法的方式 打印(a.getLastName()) 至 打印(一个:getLastName())
我已经改变了变量定义:
appUser._lname 至 _lname
这样我的代码就像这样:
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)
代码似乎有效,但我想确保到目前为止我理解你的意见/答案。
答案 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()
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
为了解决这个问题,让我们看一下以下的陈述。
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函数。您正在创建一个表({...}
),为该表提供具有给定值setLastName
或Doe
的{{1}}密钥,然后将该表传递给appUser:new函数(然后提示忽略它,因为它不需要参数)。