There are three versions of the For
statement: A long version, a short version,
and a generic version. The generic version of the For
statement is also
available in long and short versions so that there are actually four different versions of the
For
statement. For reasons of clarity, however, we stick with just the three
different versions in this documentation.
1) Long version For statement:
For [Local] <var> = <expr1> To <expr2> [Step <expr3>] <loop-block> Next |
The first thing the For
statement does, is to set the variable specified
by var
to the expression specified by expr1
. Now the value of the
Step
statement passed in expr3
defines how to continue. This value is
optional. If you do not specify the Step
statement, expr3
defaults to
the value 1.
If expr3
is positive, the For
statement will check if the value of the
variable var
is less or equal to expr2
. If this is the case, the loop
will be entered and repeated until the value of var
is greater than
expr2
. At the end of each loop, expr3
is added to the value of the
variable <var>
If expr3
is negative, the For
statement will check if the value of the
variable var
is greater or equal to expr2
. If this is the case, the
loop will be entered and repeated until the value of var
is less than
expr2
. At the end of each loop, expr3
is added to the value of the
variable var
.
In case expr3
is zero, the loop will be repeated forever. Please do also
note that the expressions specified in expr2
and expr3
are only evaluated
once, namely at the start of the loop. Thus, the loop limit and step are
constant while the loop is active and cannot be modified.
An example:
For i = 1 To 100 DebugPrint(i) Next |
This code prints the numbers from 1 to 100. DebugPrint() is executed a
hundred times. When the loop exits, the variable i
has the value 101.
You see that we did not specify a Step
statement. This means that 1
is added each time the loop is repeated. If we would like to progress
with factor 2, we could use the following code:
For i = 1 To 100 Step 2 DebugPrint(i) Next |
This will print "1 3 5 7 9 ... 95 97 99". The variable i
will have a value
of 101 when the loop exits.
If we wanted to count down from 100 to 0, we would have to use a negative step value just as in the following example:
For i = 100 To 0 Step -1 DebugPrint(i) Next |
This calls DebugPrint() a hundred and one times. After the loop exits,
the variable i
has the value -1.
If you add the Local identifier before the variable initialization, the For
statement will create the iterator variable locally to the loop block. This
means, that it cannot be accessed from outside the loop block. An example:
For Local i = 1 To 50 DebugPrint(i) ; prints 1, 2, 3 ... 49, 50 Next DebugPrint(i) ; prints 0 (i is only available inside the loop) |
The advantage of For
loops that use a local iterator variable is that they
run faster than loops that use a global variable. If you do not need to
access the variable of the For
statement from outside the loop, you should
always use the Local identifier. A limitation of For
loops with the Local
identifier is that you must not assign a new value to the local iterator
value. If you need to exit the loop, use Break. Modifying the iterator
variable during the loop's execution works only without the Local identifier.
You may also want to have a look at the documentation of the Break and Continue statements. These can be used to exit from a loop or to jump to the end of it.
2) Short version For statement:
For [Local] <var> = <expr1> To <expr2> [Step <expr3>] Do <stat> |
The short version behaves exactly like the long version but you do not have
to include the Next
statement. The short For
statement has the restriction
that the loop block must only consist of one statement. If you need to
execute multiple statements in the loop block, you have to use the long
version. The identifier Do signals Hollywood that you want to use the short
version.
The first example from above could be written in the following way using
the short For
statement:
For i = 1 To 100 Do DebugPrint(i) |
3) Generic version For statement:
For <var1> [, <var2>, ...] In <expr> [Do <stat>] or [<loop-block> Next] |
The generic version of the For
statement is different from the
other two versions through the fact that it calls a user-defined function to retrieve
the values for each iteration. This fact makes the generic For
statement
suitable for a wide variety of purposes. You can write your own iterator functions
but for most cases you will likely use the inbuilt iterator functions that are provided
by functions such as Pairs(), IPairs(), or PatternFindStr().
The expression specified in expr
is evaluated only once. It has to return three
values: An iterator function, a state value, and an initial value for var1
. The
iterator function and the state value are private values and they are neither visible
nor accessible as variables during the For
loop's runtime. Once the
generic For
loop has retrieved these three values, it will start
calling the iterator function with the state value and current value of var1
as
the two arguments. The loop will be terminated as soon as var1
becomes Nil.
Most iterator functions return multiple values for each iteration. That is why you
can also specify multiple variables in the generic For
statement.
The ability to have multiple variables initialized to different iteration states
makes the generic For
statement very flexible.
Let's have a look at an example now. Consider the following table:
months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} |
We now want to be able to find out the index of a month (1 to 12) by using its
name as a reference. Of course, we could iterate over the table, compare the name
of the month to the one we are looking for, and thus find out the appropriate
index. But when dealing with larger amounts of data, it is often faster to create
a reverse table to find out the desired information. In our case, we want a table
that uses the name of the months as indices so that table["January"] returns 1,
table["February"] returns 2, and so on. We can easily create this reverse table
using the generic For
loop together with the iterator function
provided by IPairs(). The IPairs() function will
return an iterator function that returns two values: the index value as well as the
key value for each table element that is passed to it. We can use this iterator function
to reverse the table very easily:
revmonths = {} For i,v In IPairs(months) revmonths[v] = i + 1 Next |
Alternatively, we could also use the short version of the generic For
statement for this code because there is only one statement in the For
loop. Using the short version of the generic For
statement the code
would look like this:
revmonths = {} For i,v In IPairs(months) Do revmonths[v] = i + 1 |
The IPairs() function will only iterate over all integer indices in a table. If you want to traverse all fields of a table, you can use the Pairs() function instead.
Another command that is often used in conjunction with the generic For
statement is the PatternFindStr() function. It will return an
iterator function that can be used to parse a string. For example, the following code will
iterate over all words in a string:
s$ = "Hello World This is a test" For w$ In PatternFindStr(s, "%a+") Do Print(w$) |
Of course, it is also possible to write own iterator functions. This, however, can get quite complicated. That is why it is not explained here. Please consult the book "Programming in Lua (second edition)" by Roberto Ierusalimschy for more information on how to write own iterator functions.