I want to create a very simple object oriented program. How can I list object fields (e.g., all customer names)? What is wrong with the following code? for k, v in ipairs() didn't work.
do
local Account = {}
function Account:Current()
return self.B
end
function Account:Deposit(D)
self.B = self.B + D
end
function Account:Withdraw(W)
self.B = self.B - W
end
function BankAccount(Id, Name, N)
return {B=N,Current=Account.Current,Deposit=Account.Deposit,Withdraw=Account.Withdraw,AccountName=Name,AccountId=Id}
end
end
local Id = 1
local CustomerDatabase = {}
while true do
print("Select an option or press q to quit")
print("1. Create new customer entry")
print("5. List current customer database")
local Option = io.read("*line")
if Option == "q" then break
elseif Option == "1" then
print("Enter the name")
local Name = io.read("*line")
print("Enter initial amount")
local InitialAmount = io.read("*line")
BankAccount(Id, Name, InitialAmount)
table.insert(CustomerDatabase, BankAccount)
Id = Id + 1
elseif Option == "5" then
for k, v in ipairs(CustomerDatabase) do
print(k .. v.AccountName)
end
end
end
BankAccount(Id, Name, InitialAmount)
table.insert(CustomerDatabase, BankAccount)
Here, BankAccount is a function, you are inserting into the table a function. That's why v.AccountName is invalid, functions can't be indexed.
What you should do is to add the account object:
local account = BankAccount(Id, Name, InitialAmount)
table.insert(CustomerDatabase, account)
Related
function GetCharacterName(source)
local xPlayer = QBCore.Functions.GetPlayer(source)
local name = xPlayer.PlayerData.charinfo.lastname
local name2 = xPlayer.PlayerData.charinfo.firstname
if xPlayer then
return name, name2
end
end
I'm trying to return the values of name and name2, however the return is only giving the first value. I'm newer to lua, and code in general, so just trying to learn
Additional places in which this function is called:
AddEventHandler("mdt:attachToCall", function(index)
local usource = source
local charname = GetCharacterName(usource)
local xPlayers = QBCore.Functions.GetPlayers()
for i= 1, #xPlayers do
local source = xPlayers[i]
local xPlayer = QBCore.Functions.GetPlayer(source)
if xPlayer.PlayerData.job.name == 'police' then
TriggerClientEvent("mdt:newCallAttach", source, index, charname)
end
end
TriggerClientEvent("mdt:sendNotification", usource, "You have attached to this call.")
end)
RegisterServerEvent("mdt:performVehicleSearchInFront")
AddEventHandler("mdt:performVehicleSearchInFront", function(query)
local usource = source
local xPlayer = QBCore.Functions.GetPlayer(usource)
if xPlayer.job.name == 'police' then
exports['ghmattimysql']:execute("SELECT * FROM (SELECT * FROM `mdt_reports` ORDER BY `id` DESC LIMIT 3) sub ORDER BY `id` DESC", {}, function(reports)
for r = 1, #reports do
reports[r].charges = json.decode(reports[r].charges)
end
exports['ghmattimysql']:execute("SELECT * FROM (SELECT * FROM `mdt_warrants` ORDER BY `id` DESC LIMIT 3) sub ORDER BY `id` DESC", {}, function(warrants)
for w = 1, #warrants do
warrants[w].charges = json.decode(warrants[w].charges)
end
exports['ghmattimysql']:execute("SELECT * FROM `player_vehicles` WHERE `plate` = #query", {
['#query'] = query
}, function(result)
local officer = GetCharacterName(usource)
TriggerClientEvent('mdt:toggleVisibilty', usource, reports, warrants, officer, xPlayer.job.name)
TriggerClientEvent("mdt:returnVehicleSearchInFront", usource, result, query)
end)
end)
end)
end
end)
There are two possible reasons.
name2 is nil
you're using the function call in a way that adjusts the number of return values to 1. This happens GetCharacterName(source) is not the last in a list of expressions or if you put that function call into parenthesis or you assign it to a single variable.
Edit:
Now that you've added examples of how you use that function:
local charname = GetCharacterName(usource)
In this case the result list of GetCharacterName is ajdusted to 1 value (name) as you only assingn to a single variable. If you want both return values you need two variables.
Either do it like so:
local lastName, firstName = GetCharactername(usource)
local charName = lastName .. ", " .. firstname
Then charName is "Trump, Donald" for example.
Or you return that name as a single string:
function GetCharacterName(source)
local xPlayer = QBCore.Functions.GetPlayer(source)
local name = xPlayer.PlayerData.charinfo.lastname
local name2 = xPlayer.PlayerData.charinfo.firstname
if xPlayer then
return name .. ", " .. name2
end
end
Then local charname = GetCharacterName(usource) will work
local name1, name2 = GetCharactersName()
I am working on this exercise in pil4.
Exercise 15.5:
The approach of avoiding constructors when saving tables with cycles is too radical. It is
possible to save the table in a more pleasant format using constructors for the simple case, and to use
assignments later only to fix sharing and loops. Reimplement the function save (Figure 15.3, “Saving
tables with cycles”) using this approach. Add to it all the goodies that you have implemented in the previous
exercises (indentation, record syntax, and list syntax).
I have tried this with the code below, but it seems not to work on the nested table with a string key.
local function basicSerialize(o)
-- number or string
return string.format("%q",o)
end
local function save(name,value,saved,indentation,isArray)
indentation = indentation or 0
saved = saved or {}
local t = type(value)
local space = string.rep(" ",indentation + 2)
local space2 = string.rep(" ",indentation + 4)
if not isArray then io.write(name," = ") end
if t == "number" or t == "string" or t == "boolean" or t == "nil" then
io.write(basicSerialize(value),"\n")
elseif t == "table" then
if saved[value] then
io.write(saved[value],"\n")
else
if #value > 0 then
if indentation > 0 then io.write(space) end
io.write("{\n")
end
local indexes = {}
for i = 1,#value do
if type(value[i]) ~= "table" then
io.write(space2)
io.write(basicSerialize(value[i]))
else
local fname = string.format("%s[%s]",name,i)
save(fname,value[i],saved,indentation + 2,true)
end
io.write(",\n")
indexes[i] = true
end
if #value > 0 then
if indentation > 0 then io.write(space) end
io.write("}\n")
else
io.write("{}\n")
end
saved[value] = name
for k,v in pairs(value) do
if not indexes[k] then
k = basicSerialize(k)
local fname = string.format("%s[%s]",name,k)
save(fname,v,saved,indentation + 2)
io.write("\n")
end
end
end
else
error("cannot save a " .. t)
end
end
local a = { 1,2,3, {"one","Two"} ,5, {4,b = 4,5,6} ,a = "ddd"}
local b = { k = a[4]}
local t = {}
save("a",a,t)
save("b",b,t)
print()
And I got the wrong ouput.
a = {
1,
2,
3,
{
"one",
"Two",
}
,
5,
{
4,
5,
6,
}
a[6]["b"] = 4
,
}
a["a"] = "ddd"
b = {}
b["k"] = a[4]
How could I make the text ' a[6]["b"] = 4 ' jump out of the table constructor?
How i can add to table only max 10 users ?
Because i saving scoretbl in txt, and this file have more 100 lines :/ So i want save only 10 users.
I don't know how can i check there is username in the table, and don't add this user or not this username in the table and add it?
Example:
local scoretbl = {}
local num = 0
for i=1, 10 do
table.insert(scoretbl,{'Name '..i, 100 + num})
num = num + 100
end
local function AddToTable(name, score)
if table.HasValue(scoretbl,name) then return end // hmm its not work ?
table.insert(scoretbl,{name, score})
end
AddToTable('User 55', 5454)// 11 user
AddToTable('User 55', 5454)// check: only one username in table
AddToTable('User 32', 5454)// 12 user
local function ShowOnly10()
table.sort( scoretbl, function( a, b ) return a[2] > b[2] end )
//table.remove(scoretbl,#scoretbl) remove last index in table, if i need only 10 value, i need delete in cycle ?
for k, v in pairs(scoretbl) do
print(k ,v[1], v[2])
end
end
ShowOnly10()
// upd: maybe its fix username ?
local function AddToTable(name, score)
for k, v in pairs(scoretbl) do
if v[1] == name then return false end
end
table.insert(scoretbl,{name, score})
end
I recommend that you make use of Lua's hashtable, v.name and v.score are easier to read than v[1] and v[2].
The function table.HasValue does not exist. You have to write your own.
When you want to print only the first ten elements, you should only iterate over the first ten (or up to the length of the table if it is less than ten elements long).
Line comments in Lua start with --, not //.
local scoretbl = {}
for i = 1,10 do
table.insert(scoretbl, { name = 'Name '..i, score = 100*i })
end
local function AddToTable(name, score)
-- Walk the whole table to find whether a name exists
for i,v in ipairs(scoretbl) do
if v.name == name then
-- if the record is present, update it
scoretbl[i].score = score
return
end
end
-- Insert new record
table.insert(scoretbl, { name = name, score = score })
end
AddToTable('User 55', 5454) -- 11 users
AddToTable('User 55', 5454) -- check: only one username in table
AddToTable('User 32', 5454) -- 12 users
local function ShowOnly10()
table.sort(scoretbl,function(a,b) return a.score > b.score end)
for i = 1,math.min(#scoretbl,10) do
print(i, scoretbl[i].name, scoretbl[i].score)
end
end
ShowOnly10()
I'v made a quiz with multiple choices. Before starting the game, a user has to use an identifier and then the user is added to the table and ready to play:
function addUser(msg)
local id = msg.from.username
if (userScore == nil) then
userScore = {}
end
if (userScore[id]) then
return "user already in Game"
else
userScore[id] = 100
return id
end
This adds the points in the table:
function addScore(msg)
local id = msg.from.username
if (userScore[id] == nil) then
return "user unknown. start het spel!"
end
if (game == "on") then
if (userScore[id]) then
userScore[id] = userScore[id] - 1
return id .. ", punje eraf!"
else
return id .. " is not yet a user! where to start huh?"
end
else
return "Game mode is off"
end
end
Then with !score the users can see the score:
elseif (matches[1] == "!score") then
for k, v in pairs(userScore) do
return k .. " : " .. v
end
The issue I have is that I only see one line in the table, knowing that other users are added to the table. What am I doing wrong?
From the comments it seems you want to return a single string that contains the userScore table's key-value pairs on each line.
You can do this by constructing a string that has the lines.
For example like this:
local res = {}
for k, v in pairs(userScore) do
table.insert(res, k .. " : " .. v)
end
return table.concat(res, "\n")
From what I've read on this site the below should work.
Can some kindly soul please point out where I'm going wrong?
I've embedded more description and print returns in the code hopefully to make easier reading
local m = {
{opt = "Solar Panels", cmd = "solarPanel"}
-- There are many more options here.
}
function doTheMenu()
print("Welcome to Spyder's Factory")
print("")
print("What would you like to make?")
local n = 1
local l = #m - 1
while true do --This while loop may or may not be relevant to the question, it's the menu
term.clear() --this is ComputerCraft lua, the term function is defined
term.setCursorPos(1,2) --elsewhere in an API
for i, j in pairs(m) do
if i == n then
if i < 10 then print(i, " ["..j.opt.."]") else print(i, " ["..j.opt.."]") end
fsel = j.cmd --set fsel to the function name I require in case of a break
tsel = j.opt --Ditto, tsel, human-friendly name
else
if i < 10 then print(i, " "..j.opt) else print(i, " "..j.opt) end
end
end
local a, b = os.pullEvent("key")
if b == 200 and n > 1 then n = n - 1 end
if b == 208 and n <= l then n = n + 1 end
if b == 28 then break end
end
write("\nSure, how many "..tsel.."? ")
qty = tonumber(read())
req[fsel] = req[fsel] + qty
str = fsel.."("..qty..")"
print("Loading function '"..fsel.."("..qty..")'") --Returns "Loading function 'solarPanel(1)'"
func = loadstring(str)
print(func) --Returns "function: 2cdfc5a7"
print("Loading function")
func() --The error line, Returns "string:1: attempt to call nil"
--tellUserWhatNeed()
--makeItHappen()
end
doTheMenu()
The issue is the code fails to run with the error:
string:1 attempt to call nil
Also what is term variable, if that's all your code, term is not defined and is null)
That said: either _G[fsel] is nil or fsel is nil ?
Are you sure you have function declared in _G with the name stored in fsel?
e.i. call before the problem line print (_G[fsel]) to see what it gives you.
This was the solution that ended up working:
local f = loadstring(str)
if f then
setfenv(f, getfenv())
f()
end
This replaces the lines above:
print("Loading function '"..fsel.."("..qty..")'")
func = loadstring(str)
print(func)
print("Loading function")
func()
As well as adding basic error handling for loading the function