Without giving too much details, this sample snippet demonstrates the problem:
-- Add an extra predefined argument
function one_more_arg(...)
local args = {...}
return function()
print(table.unpack(args), "c")
end
end
local my_new_print = one_more_arg("a", "b")
my_new_print() -- "a c"
Apparently unpacking a table does not work in this scenario. Any ideas on how to make this work, ie print will receive "a", "b", "c"? I'm trying to avoid modifying args, unless it's the only way to achieve it.
When you place table.unpack() as an argument to function there should be no other arguments or it should be the last one. Otherwise only first value from table will be passed.
Lua always adjusts the number of results from a function to the
circumstances of the call. When we call a function as a statement, Lua
discards all of its results. When we use a call as an expression, Lua
keeps only the first result. We get all results only when the call is
the last (or the only) expression in a list of expressions. These
lists appear in four constructions in Lua: multiple assignment,
arguments to function calls, table constructors, and return
statements.
From http://www.lua.org/pil/5.1.html
So you can try to put unpack at the end if it is ok for you:
print("c", table.unpack(args))
Or modify args.
table.concat (list [, sep [, i [, j]]])
Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string.
Related
I am confused by the following output:
local a = "string"
print(a.len) -- function: 0xc8a8f0
print(a.len(a)) -- 6
print(len(a))
--[[
/home/pi/test/wxlua/wxLua/ZeroBraneStudio/bin/linux/armhf/lua: /home/pi/Desktop/untitled.lua:4: attempt to call global 'len' (a nil value)
stack traceback:
/home/pi/Desktop/untitled.lua:4: in main chunk
[C]: ?
]]
What is the proper way to calculate a string length in Lua?
Thank you in advance,
You can use:
a = "string"
string.len(a)
Or:
a = "string"
a:len()
Or:
a = "string"
#a
EDIT: your original code is not idiomatic but is also working
> a = "string"
> a.len
function: 0000000065ba16e0
> a.len(a)
6
The string a is linked to a table (named metatable) containing all the methods, including len.
A method is just a function, taking the string as the first parameter.
function a.len (string) .... end
You can call this function, a.len("test") just like a normal function. Lua has a special syntax to make it easier to write. You can use this special syntax and write a:len(), it will be equivalent to a.len(a).
print(a.len) -- function: 0xc8a8f0
This prints a string representation of a.len which is a function value. All strings share a common metatable.
From Lua 5.4 Reference Manual: 6.4 String Manipulation:
The string library provides all its functions inside the table string.
It also sets a metatable for strings where the __index field points to
the string table. Therefore, you can use the string functions in
object-oriented style. For instance, string.byte(s,i) can be written
as s:byte(i).
So given that a is a string value, a.len actually refers to string.len
For the same reason
print(a.len(a))
is equivalent to print(string.len(a)) or print(a:len()). This time you called the function with argument a instead of printing its string representation so you print its return value which is the length of string a.
print(len(a))
on the other hand causes an error because you attempt to call a global nil value. len does not exist in your script. It has never been defined and is hence nil. Calling nil values doesn't make sense so Lua raises an error.
According to Lua 5.4 Reference Manual: 3.4.7 Length Operator
The length of a string is its number of bytes. (That is the usual
meaning of string length when each character is one byte.)
You can also call print(#a) to print a's length.
The length operator was introduced in Lua 5.1,
Luas string.format is pretty straight forward, if you know what to format.
However, I stuck at writing a function which takes a wildcard-string to format, and a variable number of arguments to put into that blank string.
Example:
str = " %5s %3s %6s %6s",
val = {"ttyS1", "232", "9600", "230400"}
Formatting that by hand is pretty easy:
string.format( str, val[1], val[2], val[3], val[4] )
Which is the same as:
string.format(" %5s %3s %6s %6s", "ttyS1, "232", "9600","230400")
But what if I wan't to have a fifth or sixth argument?
For example:
string.format(" %1s %2s %3s %4s %5s %6s %7s %", ... )
How can I implement a string.format with an variable number of arguments?
I want to avoid appending the values one by one because of performance issues.
The application runs on embedded MCUs.
Generate arbitrary number of repeats of whatever format you want with string.rep if format is the same for all arguments. Or fill table with all formats and use table.concat. Remember that you don't need to specify index of argument in format if you don't want to reorder them.
If you just need to concatenate strings together separated by space, use more suitable tool: table.concat(table_of_strings, ' ').
You can create a table using varargs:
function foo(fmt, ...)
local t = {...}
return t[6] -- might be nil
end
Ps, don't use # on the table if you expect the argument list might contain nil. Instead use select("#", ...).
I want to use erlang datetime values in the standard format {{Y,M,D},{H,Min,Sec}} in a MNESIA table for logging purposes and be able to select log entries by comparing with constant start and end time tuples.
It seems that the matchspec guard compiler somehow confuses tuple values with guard sub-expressions. Evaluating ets:match_spec_compile(MatchSpec) fails for
MatchSpec = [
{
{'_','$1','$2'}
,
[
{'==','$2',{1,2}}
]
,
['$_']
}
]
but succeeds when I compare $2 with any non-tuple value.
Is there a restriction that match guards cannot compare tuple values?
I believe the answer is to use double braces when using tuples (see Variables and Literals section of http://www.erlang.org/doc/apps/erts/match_spec.html#id69408). So to use a tuple in a matchspec expression, surround that tuple with braces, as in,
{'==','$2',{{1,2}}}
So, if I understand your example correctly, you would have
22> M=[{{'_','$1','$2'},[{'==','$2',{{1,2}}}],['$_']}].
[{{'_','$1','$2'},[{'==','$2',{{1,2}}}],['$_']}]
23> ets:match_spec_run([{1,1,{1,2}}],ets:match_spec_compile(M)).
[{1,1,{1,2}}]
24> ets:match_spec_run([{1,1,{2,2}}],ets:match_spec_compile(M)).
[]
EDIT: (sorry to edit your answer but this was the easiest way to get my comment in a readable form)
Yes, this is how it must be done. An easier way to get the match-spec is to use the (pseudo) function ets:fun2ms/1 which takes a literal fun as an argument and returns the match-spec. So
10> ets:fun2ms(fun ({A,B,C}=X) when C == {1,2} -> X end).
[{{'$1','$2','$3'},[{'==','$3',{{1,2}}}],['$_']}]
The shell recognises ets:fun2ms/1. For more information see ETS documentation. Mnesia uses the same match-specs as ETS.
In my lua script I need to call a function which takes an arbritary number of arguments with, well, an arbitrary number of arguments…
I am building up my arguments as a table as I cant know how many arguments there will be.
Sample code:
local result = call.someFunc();
local arguments = {}
for k,v in pairs(result) do
table.insert(arguments, v.name)
end
-- here I would like to somehow pass the whole table and each item in the table
-- is then passed as a single argument to "someOtherFunc"
call.someOtherFunc(arguments[1], arguments[2], arguments[3] ....)
I am pretty new to lua, in PHP e. g. I would use call_user_func_array – is there something similiar in lua?
foo(unpack(arguments)) is equivalent to foo(arguments[1], arguments[2], ...).
The long answer can be found on the Lua Users' Wiki.
This covers everything including trailing nil arguments.
Just pass the table as the argument. No need to split it up into single arguments, just have the function loop through the table.
I'm confused by behavior I'm seeing when I use luaxml to parse an XML string. The Lua doc states that calling print() on a table variable as such:
print(type(t))
print(t)
will result in output like this:
t2: table
t2: table: 0095CB98
However, when I use luaxml as such:
require "luaxml"
s = "<a> <first> 1st </first> <second> 2nd </second> </a>"
t = xml.eval(s)
print("t: ", type(t))
print("t: ", t)
I get the following output:
t: table
t: <a>
<first>1st</first>
<second>2nd</second>
</a>
Why does print(t) not return a result that looks like the first example?
The print function uses tostring to convert its arguments to strings.
When tostring is called with a table, and the table's metatable has a __tostring field, then tostring calls the corresponding value with the table as an argument, and uses the result of the call as its result.
I suspect that luaxml has such a __tostring metamethod on the table returned from xml.eval(s).
You can define the function __tostring on a table's metatable to get this result. When you pass that table to print(), if you have a __tostring function on your metatable, print() will output the result of evaluating that function instead of using the default method (which just prints the memory address of the table).