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
Related
local a = {'1'}
b = {'2'}
print('--------a:', a) --------a: table: 002411A0
print('--------b:', b) --------b: table: 005BC470
how can I get like: a.lua:1 in table a
or a.lua:2 in table b
while I know the table address (002411A0)
my lua environment is lua5.1, I don't know if I need to read the source or compiled of lua5.1?
If you are prepared to declare your tables with a helper function, called, say logger, you can achieve your goal.
The idea is to record the line in a virtual table field __line. In the example below I do it using __index metamethod, but you can simply add a field to the created table.
The line number is obtained by debug.getinfo (2).currentline. The choice of 2 is determined by the call stack depth in my example.
local function logged (t)
local line = debug.getinfo (2).currentline
return setmetatable (t, {
__index = function (_, key)
if key == '__line' then
return line
end
end
})
end
local a = logged {'1'}
print (a.__line) -- 12
b = logged {'2'}
print (b.__line) -- 14
There is no way to get a line where the table is defined by using its address (as the line in the source code and the address in memory have no relationship). What you can do is to parse the source code of your script and find where the definition of the table is, but I'm not sure what use it's going to have for you. Maybe you can describe what you are trying to do?
If you indeed want to find where the table is defined, you can use something like metalua that builds abstract syntax tree (AST) of your code fragment that you can then traverse to find where a particular table is defined.
Another option is to parse the output of luac compiler, which will allow you to find what line the NEWTABLE command for a particular table is on.
This seems like a very straightforward question, but I haven't been able to turn up an answer. I am adding game objects to a table in Lua like this:
local lock = GameObject {
-- object values and methods
table.insert(objects, lock)
But despite a lot of google searching and reading through the Lua documentation, I cannot figure out how to reference these objects by their names. I think it's because there is a very specific syntax to do so. If anyone could help me out, I would greatly appreciate it. Thanks!
You might want to do something like this instead of table.insert. Objects will still be a table.
objects = {}
objects.lock = {}
objects.lock2 = {}
If you then execute
for key, value in pairs(objects) do
print(key,value)
end
You will get the output
lock2 table: 0x1af3310
lock table: 0x1af3870
Further explanation
In you question(not the solution above) lock is only the variable name given to it, it is not the name of the index.
In this code snippet, you can see that the items being inserted into objects do not have the variable name recorded within objects. objects is storing an int as the key, and then the inserted table as the value.
objects = {}
local lock = {}
local lock2 = {}
-- object values and methods
table.insert(objects, lock)
table.insert(objects, lock2)
for key, value in pairs(objects) do
print(key,value)
print(type(value))
end
prints
1 table: 0x131b590
table
2 table: 0x131b540
table
test it on repl
I got a question on how to use dynamic variable names with the table.insert function in Lua.
I want to create some tables with dynamic variable names and afterwards access those tables using table.insert function to fill them with values, however, I am unclear on how to access the newly created table inside of the table.insert function.
My code so far looks like this:
local attributeNames = {"attribute1","attribute2","attribute3"}
local attributes = {}
for k, v in pairs(attributeNames) do
// If attribute name equals name of type then create a new table with
that type name
if(string.match(v, type)) then
attributes[v] = {}
currentAttribute = v
break
end
end
// Insert values into the table with that type name, here I do not get how to call
the table of name "attribute1" for example to fill it with values
table.insert (attributes[currentAttribute], values)
Any help is highly welcome! :)
I am confused of the following two syntaxes using "."
From what I understand, __index is called when a key doesn't exist in a table but exists in its metatable. So why does the list table call __index and then assign itself to list.__index?
list = {}
list.__index = list
setmetatable(list, { __call = function(_, ...)
local t = setmetatable({length = 0}, list)
for _, v in ipairs{...} do t:push(v) end
return t
end })
function list:push(t)
if self.last then
self.last._next = t
t._prev = self.last
self.last = t
else
self.first = t
self.last = t
end
self.length = self.length + 1
end
.
.
.
local l = list({ 2 }, {3}, {4}, { 5 })
Does Window.mt simply create a table? Why do we need Window = {} as a namespace here?
Window = {} -- create a namespace
Window.mt = {} -- create a metatable
Window.prototype = {x=0, y=0, width=100, height=100, }
function Window.new (o)
setmetatable(o, Window.mt)
return o
end
Window.mt.__index = function (table, key)
return Window.prototype[key]
end
w = Window.new{x=10, y=20}
print(w.width) --> 100
So why does the list table call __index and then assign itself to list.__index?
Nowhere in your code does the list table call __index. The assignment part however is a common Lua idiom (aka. hack) to save some memory. Conceptually there are 4 different kinds of tables involved:
list objects (the tables created via {length=0} in your code)
a metatable (containing an __index field) that modifies the behavior of list objects when you try to access non-existing fields in the object
the list class, which holds all the methods for list objects (like the push method), and also serves as a constructor for list objects
a metatable (containing a __call field) for the list class, so that you can call the list table as if it were a function
As metatable fields always start with two underscores (__), and normal methods usually don't, you can put metatable fields and normal methods side by side into a single table without conflict. And this is what happened here. The list class table also serves as metatable for list objects. So using this trick you can save the memory you would normally need for the separate metatable (the size in bytes for Lua 5.2 on an x86-64 Linux is shown in square brackets in the table title bars, btw.):
Does Window.mt simply create a table?
No, {} creates a table. However, this new table is saved under key "mt" in the Window table, probably to give users of this Window "class" direct access to the metatable that is used for window objects. Given only the code you showed this is not strictly necessary, and you could have used a local variable instead.
Why do we need Window = {} as a namespace here?
In principle, you could store Window.mt, Window.new, and Window.prototype separately, but that would get cumbersome if you have multiple "classes" like Window. This way you can avoid name clashes, and using the Window "class" looks nicer.
Another reason might be that require can only return a single value from a module definition, and if you want to export multiple values (like new, mt, and prototype) from a module, you need a table to wrap them together (or use global variables, but that is considered bad style).
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!