Lua execute something stored in tables key value - lua

I want to make a table with specific names as keys and specific functions as values.
The key names represent commands that a user enters and if a key by that name exists, then the program should execute the code stored in that keys value.
So for example, we make a table with keys and functions inside the key value:
local t = {
["exit"] = quitGame,
...,
...
}
and we also have a function for example:
function quitGame()
print("bye bye")
os.exit()
end
so now we do:
userInput = io.read()
for i,v in pairs(t) do
if userInput == i then
--now here, how do I actually run the code that is stored in that key value (v)?
end
end
I hope you understand what I'm trying to do.

You have a table keyed by value. There's no need to loop to find the key you want. Just look it up directly. Then just call the value you get back.
local fun = t[userInput]
if fun then
fun()
end

Related

LUA - Getting values from nested table

I have a table which will be used to store each players name, id and another value
{
{
rpname = "name",
SteamID = "STEAM_0:0:",
giftsFound = "1",
},
The table is being sent from server to client via net.ReadTable()
I want to be able to choose each value seperatley but when I have tried the following below it only returns the first letter of every value instead of the first value
for k, v in pairs(tableData) do
for k, v in pairs(v) do
print(v[1]
end
end
Please could somebody help me out?
If I understood correctly, the sample table you wrote in the first block of code would be what you called tableData in the second, right? So, what you want to have is:
An array of players
Each entry in this array is a table
A way of getting each field of each player
With a few tweaks we can make your code more readable and, from that, correct it. Firsly, I would rename some things:
Rename your table players, for it is an array of players
local players = {
{
rpname = "john",
SteamID = "STEAM_0:0:1",
giftsFound = "4",
},
-- [...]
}
Rename your variables in the for-loop
In Lua it is common pratice to use _ to name variable we are not going to use. In this case, the key (originally named k) is not something we will use.
Since it is a list of players, each entry is a player, so it is logical to rename the variable v to player.
Also, I changed pairs() to ipairs() and there's a good reason for that. I won't cover it here, but here it is explained as best as I could. Rule of thumb: if your table is array-like, use ipairs(); else, use pairs().
for _, player in ipairs(players) do
-- [...]
end
For the nested for-loop, it does make sense using k, v and pairs, so it would be something like this:
for k, v in pairs(player) do
print(k,v)
end
Running the full piece would produce this:
rpname john
giftsFound 4
SteamID STEAM_0:0:1
I suppose it solves your problem. The real errors in your code were the way you tried to access the nested table field and, arguably, naming variables with names you have already used (k and v) in the same scope, which is, in the best case, misleading.
If you want to access a specific field in the table, instead of going through the whole thing, you can do:
-- To print every player's name
for _, player in ipairs(players) do
local name = player.rpname
print(name)
end
Or even:
-- To get the first player's (in the array) name
local name = players[1].rpname
One last thing: "Lua" is not an acronym, you don't need to use all capital letters. Lua was created in Brazil and here we speak portuguese. Lua means Moon in portuguese.

Strange bug with table in lua

I'm adding a string to a table in lua. When I use the table in a function the original table is getting altered. I'm only a beginner but I thought that the function could not do that because it is outside of it's scope. Is there something obvious I'm missing?
local testTable= {}
testTable.name = {}
testTable.name[1] = "Jon"
print(testTable.name[1])
local function testFunc(a)
a.name[1] = "Bob"
end
local newTable = testTable
testFunc(newTable)
print(testTable.name[1])
I expected the output to be:
Jon
Jon
The actual output is:
Jon
Bob
How can the testFunc change the testTable?
You assign testTable's address to newTable, so testTable and newTable point to the same table.
If you want to output be
Jon
Jon
You should copy the table when you assign newTable.
You can copy the table like this function:
function table.copy(old)
local new = {}
for k, v in pairs(old) do
new[k] = v
end
return new
end
When I use the table in a function the original table is getting altered. ... I thought that the function could not do that because it is outside of it's scope.
Local variables have their own scope, but tables do not. Two things to remember:
Variables store references, not values. (This only makes a difference for mutable values.)
Tables are mutable, i.e., they can be changed internally.
Breaking it down:
local newTable = testTable
In this line, you're assigning one variable to another, so both variables refer to the same table.
We mutate a table by assigning to an index within that table, so testFunc alters whatever a (actually a.name) refers to. This is handy, because it allows us to write functions that mutate tables that we pass as arguments.
The following function does nothing, like you would expect, because it assigns a new table to the bare name a (which happens to be a local variable):
local function doNothing(a)
a = {name = {'Bob'}}
end

Lua:how to create a custom method on all tables

I'd like to create a custom contains method on Lua's table data structure that would check for the existence of a key. Usage would look something like this:
mytable = {}
table.insert(mytable, 'key1')
print(mytable.contains('key1'))
Thanks.
In Lua you cannot change ALL tables at once. You can do this with simpler types, like numbers, strings, functions, where you can modify their metatable and add a method to all strings, all functions, etc. This is already done in Lua 5.1 for strings, this is why you can do this:
local s = "<Hello world!>"
print(s:sub(2, -2)) -- Hello world!
Tables and userdata have metatables for each instance. If you want to create a table with a custom method already present, a simple table constructor will not do. However, using Lua's syntax sugar, you can do something like this:
local mytable = T{}
mytable:insert('val1')
print(mytable:findvalue('val1'))
In order to achieve this, you have to write the following prior to using T:
local table_meta = { __index = table }
function T(t)
-- returns the table passed as parameter or a new table
-- with custom metatable already set to resolve methods in `table`
return setmetatable(t or {}, table_meta)
end
function table.findvalue(tab, val)
for k,v in pairs(tab) do
-- this will return the key under which the value is stored
-- which can be used as a boolean expression to determine if
-- the value is contained in the table
if v == val then return k end
end
-- implicit return nil here, nothing is found
end
local t = T{key1='hello', key2='world'}
t:insert('foo')
t:insert('bar')
print(t:findvalue('world'), t:findvalue('bar'), t:findvalue('xxx'))
if not t:findvalue('xxx') then
print('xxx is not there!')
end
--> key2 2
--> xxx is not there!

Can I detect the moment of a value is just assigned to a table in Lua?

I made an interactive command shell which is operating by Lua interpreter. User input some command, shell calls something like lua_dostring to execute it. I want to allow users to define their own functions in arbitrary table, and save it to separated storage (like a file) automatically. According to the manual, I can get exact source code input by user with lua_Debug.
It looks possible to save the functions sources to some files after all execution done. But I want to save automatically when it's just added/remove.
Can I detect the moment of some value is just added to a table?
Yes. If you have a table tbl, every time this happens:
tbl[key] = value
The metamethod __newindex on tbls metatable is called. So what you need to do is give tbl a metatable and set it's __newindex metamethod to catch the input. Something like this:
local captureMeta = {}
function captureMeta.__newindex(table, key, value)
rawset(table, key, value)
--do what you need to with "value"
end
setmetatable(tbl, captureMeta);
You will have to find a way to set the metatable on the tables of interest, of course.
Here's another way to do this with metatables:
t={}
t_save={}
function table_newinsert(table, key, value)
io.write("Setting ", key, " = ", value, "\n")
t_save[key]=value
end
setmetatable(t, {__newindex=table_newinsert, __index=t_save})
Here's the result:
> t[1]="hello world"
Setting 1 = hello world
> print(t[1])
hello world
Note that I'm using a second table as the index to hold the values, instead of rawset, since __newindex only works on new inserts. The __index allows you to get these values back out from the t_save table.

using type() function to see if current string exist as table

Is it possible to see if a string is the same as the name of a table?
For example:
I know that a table called 'os' exists, and I have a string "os".
Is there then a way to do this:
x="os"
if type(x)=="table" then
print("hurra, the string is a table")
end
Of course this example wont work like I want it to because
type(x)
will just return "string".
The reason why I want to do this, is just because I wanted to list all existing Lua tables, so I made this piece of code:
alphabetStart=97
alphabetEnd=122
function findAllTables(currString, length)
if type(allTables)=="nil" then
allTables={}
end
if type(currString)=="table" then
allTables[#allTables+1]=currString
end
if #currString < length then
for i=alphabetStart, alphabetEnd do
findAllTables(currString..string.char(i), length)
end
end
end
findAllTables("", 2)
for i in pairs(allTables) do
print(i)
end
I wouldn't be surprised if there is an easier method to list all existing tables, I'm just doing this for fun in my progress of learning Lua.
If you want to iterate over all global variables, you can use a for loop to iterate over the special _G table which stores them:
for key, value in pairs(_G) do
print(key, value)
end
key will hold the variable name. You can use type(value) to check if the variable is a table.
To answer your original question, you can get a global variable by name with _G[varName]. So type(_G["os"]) will give "table".
interjay gave the best way to actually do it. If you're interested, though, info on your original question can be found in the lua manual. Basically, you want:
mystr = "os"
f = loadstring("return " .. mystr);
print(type(f()))
loadstring creates a function containing the code in the string. Running f() executes that function, which in this case just returns whatever was in the string mystr.

Resources