I would like to increment a variable after each range loop. However it seems it's not possible using the standard ( for init; condition; post { } ) for syntax therefore I'm wondering why . Here is what I'm trying to do
for item := range itemsList; page++ {
}
It seems the only way to do this is
for item := range itemsList{
page++
}
which doesn't look as nice as the first one.
The for statement specification does mention that a Range Clause stands alone.
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
As opposed to a Post Statement, which is part of:
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
That means a post statement is only valid in the context of an initialization and a condition, in order to potentially make that condition change (since it is executed after each execution of the block, and only if the block was executed).
There is no such need (making a condition stops a loop) in a Range clause, where the fact that the loop has been done over all the elements of a range (of an array, slice, string, map, or channel permitting receive operations) is enough for the loop to stops.
A range expression is evaluated once before beginning the loop (or at least its length is). There is no need to change anything after each execution of the block.
So trying to add a post statement to a range loop would generate a compilation error like:
expected '{', found ';'
Related
I'm trying to build a new list of structs that contains references to items that exist in another slice. It's easier to understand if you see it, so I've prepared a snippet that you can run.
I have a list (dummylist) of two points (Cartesian coordinates) that I want to parse to build a new list (mylist) with items having some features (in the example, X > 80). I've defined two points: {X:90.0, Y:50.0} and {X:20.0 , Y:30.0}. I expect that mylist will contain {X:90.0, Y:50.0}, instead at the end there is {X:20.0 , Y:30.0}. With some print here and there I can verify that the algorithm is working fine (it enters in the "if" condition in the right case), but, at the end, "mylist" contains the wrong element.
package main
import(
"fmt"
)
func main() {
type point struct {
X float64
Y float64
}
type pointsList []point
type pointContainer struct {
Point *point
}
type pointContainerList []pointContainer
// Prepare a slice with two elements
dummylist := new(pointsList)
*dummylist = append(*dummylist, point{X:90.0, Y:50.0})
*dummylist = append(*dummylist, point{X:20.0 , Y:30.0})
// My empty list
mylist := new(pointContainerList)
fmt.Println(fmt.Sprintf("---- At the beginning, mylist contains %d points", len(*mylist)))
// Filter the initial list to take only elements
for _, pt := range *dummylist {
fmt.Println("\n---- Evaluating point ", pt)
if pt.X > 80 {
fmt.Println("Appending", pt)
*mylist = append(*mylist, pointContainer{Point: &pt})
fmt.Println("Inserted point:", (*mylist)[0].Point, "len = ", len(*mylist))
}
}
// mylist should contain {X:90.0, Y:50.0}, instead...
fmt.Println(fmt.Sprintf("\n---- At the end, mylist contains %d points", len(*mylist)))
fmt.Println("Content of mylist:", (*mylist)[0].Point)
}
Here you can run the code:
https://play.golang.org/p/AvrC3JJBLdT
Some helpful consideration:
I've seen through multiple tests that, at the end, mylist contains the last parsed item in the loop. I think there is a problem with references. It's like if the inserted item in the list (in the first iteration) is dependent on the "pt" of other iterations. Instead, if I use indexes (for i, pt := range *dummylist and (*dummylist)[i]), everything works fine.
Before talking about bugs in Golang... am I missing something?
Yes, you're missing something. On this line:
*mylist = append(*mylist, pointContainer{Point: &pt})
you're putting the address of the loop variable &pt into your structure. As the loop continues, the value of pt changes. (Or to put it another way, &pt will be the same pointer for each iteration of the loop).
From the go language specification:
...
The iteration values are assigned to the respective iteration
variables as in an assignment statement.
The iteration variables may be declared by the "range" clause using a
form of short variable declaration (:=). In this case their types are
set to the types of the respective iteration values and their scope is
the block of the "for" statement; they are re-used in each iteration.
If the iteration variables are declared outside the "for" statement,
after execution their values will be those of the last iteration.
One solution would be to create a new value, but I'm not sure what you're gaining from so many pointers: []point would probably be more effective (and less error-prone) than a pointer to a slice of structs of pointers to points.
What does this kind of loop do in Lua?
for count = 1, 2 do
-- do stuff
end
The variable count isn't used in the body of the loop.
It executes the body of the loop twice.
There's no need to refer to count inside the loop unless you need to know its current value.
for count = 1,5 do
print("Hello")
end
prints
Hello
Hello
Hello
Hello
Hello
In this case count is "dummy variable" - "dummy" in that a variable is used fulfill a certain construct even though the variable is not used. (Another common name for such a usage is _, although count arguably adds a little more semantic intent.)
Such a dummy variable is used because LUA loops require a variable / assignment in the grammar construct. However, there is no requirement that the variable is used - hence a "dummy".
.. A numeric for [loop] has the following syntax:
for var=exp1,exp2,exp3 do
something
end
That loop will execute something for each value of var from exp1 to exp2, using exp3 as the step to increment var. This third expression [exp3] is optional; when absent, Lua assumes one [1] as the step value.
I'm writing a dice rolling function. In order to add the result of each die, I added to an output variable using a for loop. However, I'm getting an error thrown when I attempt to build;
syntax error: unexpected semicolon or newline, expecting {
This was thrown on the line initializing the for loop.
Here is my code:
for i := 0; i < [0]si; i++ {
output := output + mt.Intn([1]si)
}
si is simply an int array holding 2 values, and mt is the name I gave to math/rand when I imported it.
Your loop has several problems:
The use of square brackets is odd. Outside of type definitions, these go after slice/array names, e.g. x[i] would give you the ith element of the slice x.
There is no reference to i inside the loop body, and thus each iteration of the loop will do the same thing.
You should probably write output = output + ... without the colon. Otherwise, a new variable output is declared during each iteration of the loop, and forgotten immediately after so that the loop has no effect.
The compiler error is probably caused by the first of these problems.
You access an array with varname[idx] in Go, just like in most other languages. It's only when declaring a new array of type si that you use the [size]si prefix syntax. You're getting the error because your code is syntactically invalid. You're trying to compare i to an array of 0 si s.
I'm customising a code I found over the internet (it's the Adafruit Tweet Receipt). I cannot understand many parts of the code but the most perplexing to me is the for-loop with two semicolons inside the parentheses
boolean jsonParse(int depth, byte endChar) {
int c, i;
boolean readName = true;
for(;;) { //<---------
while(isspace(c = timedRead())); // Scan past whitespace
if(c < 0) return false; // Timeout
if(c == endChar) return true; // EOD
if(c == '{') { // Object follows
if(!jsonParse(depth + 1, '}')) return false;
if(!depth) return true; // End of file
if(depth == resultsDepth) { // End of object in results list
What does for(;;) mean? (It's an Arduino program so I guess it's in C).
for(;;) {
}
functionally means
while (true) {
}
It will probably break the loop/ return from loop based on some condition inside the loop body.
The reason that for(;;) loops forever is because for has three parts, each of which is optional. The first part initializes the loop; the second decides whether or not to continue the loop, and the third does something at the end of each iteration. It is full form, you would typically see something like this:
for(i = 0; i < 10; i++)
If the first (initialization) or last (end-of-iteration) parts are missing, nothing is done in their place. If the middle (test) part is missing, then it acts as though true were there in its place. So for(;;) is the same as for(;true;)', which (as shown above) is the same as while (true).
The for loop has 3 components, separated by semi-colons. The first component runs before the looping starts and is commonly used to initialize a variable. The second is a condition. The condition is checked at the beginning of each iteration, and if it evaluates to true, then the code in the loop runs. The third components is executed at the end of the loop, before another iteration (starting with condition check) begins, and is often used to increment a variable.
In your case for(;;) means that it will loop forever since the condition is not present. The loop ends when the code returns or breaks.
Each clause of a for loop is optional. So when they are excluded, it still loops. for loops compile into while loops.
The end result becomes a check to initialize any variables, which concludes after nothing happening since it is empty, a check to the boolean condition in the second clause, which is not present so the loop starts, and once the loop hits the end bracket, a check to see if there is any code to run before checking the boolean condition again.
In code it looks like:
while(true){
}
Here's What Wikipedia Says About it
Use as infinite loops
This C-style for-loop is commonly the source of an infinite loop since the fundamental steps of iteration are completely in the control of the programmer. In fact, when infinite loops are intended, this type of for-loop can be used (with empty expressions), such as:
for (;;)
//loop body
This style is used instead of infinite while(1) loops to avoid a type conversion warning in some C/C++ compilers.Some programmers prefer the more succinct for(;;) form over the semantically equivalent but more verbose while (true) form.
I'm executing a template with 2 parallel arrays (same size) and I want to list items from both arrays in parallel, how do I use index inside of range?
this obviously doesn't work:
{{range $i, $e := .First}}$e - {{index .Second $i}}{{end}}
One of the predefined global template functions is index.
index Returns the result of indexing its first argument by the
following arguments. Thus index x 1 2 3 is, in Go syntax,
x[1][2][3]. Each indexed item must be a map, slice, or array.
So you are on the right track. The only issue is that you are not accounting for the fact the dot has been reassigned within the range block.
So you need to get back to the original dot, for that we have the following
When execution begins, $ is set to the data argument passed to Execute, that is, to the starting value of dot.
So (assuming there is nothing else going on in your template) you should be able to do:
{{range $i, $e := .First}}$e - {{index $.Second $i}}{{end}}
Personally though, I would create a template function called zip that accepts multiple slices and returns a slice of each pair of values. It would look cleaner in your template and probably get reused somewhere.