Reputation: 1393
Is there / please suggest a syntax to achieve a compact 'test and assign' in lua?
Consider this segment from luasql examples ( http://keplerproject.org/luasql/examples.html )
-- retrieve a cursor
cur = assert (con:execute"SELECT name, email from people")
-- print all rows, the rows will be indexed by field names
row = cur:fetch ({}, "a")
while row do
print(string.format("Name: %s, E-mail: %s", row.name, row.email))
-- reusing the table of results
row = cur:fetch (row, "a")
end
I am learning lua, and really struggling to accept the duplicated call to cur:fetch(). I see that repeat/until trivially fixes the issue, but then it seems I have to test twice:
repeat
row = cur:fetch ({}, "a")
if row then
print ...
end
until nil == row
I consider this less error prone for the case of 'row = ...' getting more complex, but still seems inelegant.
Upvotes: 3
Views: 1267
Reputation: 52621
You can simplify the first loop to this:
local row = {}
while row do
row = cur:fetch(row, "a")
end
EDIT: The sample page hits at a possible solution using iterators and a for loop, like @doukremt is suggesting. Unfortunately it also contains a couple errors (it assumes that the rows get "unpacked" in the second example but not in the first, does not declare everything local
, and omits more parenthesis than it's sane to in a sample code). Here's how you can transform a cursor in an iterator:
local iterate = function(cur)
return function() return cur:fetch() end
end
Here's how you use it:
local cur = assert(con:execute("SELECT name, email from people"))
for row in iterate(cur) do
print(string.format ("%s: %s", row.name, row.email))
end
I must warn you that iterators are in general more expensive than while/repeat loops. Execute performance tests if you are worried about speed.
Upvotes: 4
Reputation: 72312
Try
while true do
local row = cur:fetch ({}, "a")
if row then
print ...
else
break
end
end
Upvotes: 3
Reputation: 8205
Just use a for loop:
row = {}
for row in cur:fetch(row, "a") do
-- ...
end
The call to fetch()
returns a pointer to the table you pass as argument, so you could as well do:
row = {}
for foobar in cur:fetch(row, "a") ...
The important point is that fetch()
returns nil when there are no more rows, so you just need to check for that, which a for loop does implicitly.
Upvotes: 3