Can someone help me understand why this is implemented this way?

While building a very simple caching system, I came across a scenario where I have a slice that, as I iterate over it, gets consumed. New incoming data gets appended onto the slice and sendoff is handled by sending off slice[0] (assuming len() > 0 checks out) and rebuilding the slice with myslice = myslice[1:]. I re-implemented something similar here:

func main() {

	var finval []int = []int{1, 2, 3, 4, 5, 6, 7}
	var lenfin = len(finval)
	//for i := 0; i < len(finval); i++{
	for i := 0; i < lenfin; i++ {
		fmt.Println(i, ":", finval[0])
		finval = finval[1:]
	}
}

I noticed that, while playing around with this simplified version, the commented out line re-checks the length of finval while iterating, leading to the output

0 : 1
1 : 2
2 : 3
3 : 4

instead of the expected and appropriate

0 : 1
1 : 2
2 : 3
3 : 4
4 : 5
5 : 6
6 : 7

It seems obvious to me that as each loop cycles over, it re-checks the length. I’m not sure why, but I would have expected the length value to be checked at the start and not changed. Am I wrong to expect this? Is there a technical reason this is implemented this way? I would have thought that some black magic involving pointers would be needed to have it re-check every loop.

It reevaluates the ending condition after each iteration and the finval length is changing inside the loop

actually for loop in Go like this

func main() {

	var finval []int = []int{1, 2, 3, 4, 5, 6, 7}
	var lenfin = len(finval)
        var i int = 0
        while i < lenfin {
                fmt.Println(i, ":", finval[0])
                finval = finval[1:]
                i++
        }
}

if you check len in loop will like this:

func main() {

	var finval []int = []int{1, 2, 3, 4, 5, 6, 7}
	var lenfin = len(finval)
        var i int = 0
        while i < lenfin {
                fmt.Println(i, ":", finval[0])
                finval = finval[1:]
                lenfin = len(finval)  // here check again 
                i++
        }
}

There is no while in go

2 Likes

There was a similar discussion here, maybe it can help you

Consider the following code:

func main() {
	shiftingTarget := 100
	for i := 0; i < shiftingTarget; i++ {
		shiftingTarget--
	}
	fmt.Println("All done and shifting target is", shiftingTarget)
}

That behaves exactly how you would expect, right? And if you invert it to for i := 0; shiftingTarget > i; i++ { you would ALSO expect it to work, right? So how would the compiler know which properties you expect to be constant? From the tour of go (emphasis mine):

The basic for loop has three components separated by semicolons:

  • the init statement: executed before the first iteration
  • the condition expression: evaluated before every iteration
  • the post statement: executed at the end of every iteration

There’s nothing special about the init/condition/post statement. You could write the following if you wanted:

func main() {
	i := 0
	for fmt.Println("init"); condition(); fmt.Println("post") {
		if i == 10 {
			break
		}
		i++
	}
}

func condition() bool {
	fmt.Println("condition")
	return true
}

That said, I think your loop would probably be more accurately and simply represented like this:

func main() {
	finval := []int{1, 2, 3, 4, 5, 6, 7}
	// Process all the items in our slice
	for len(finval) > 0 {
		fmt.Println(finval[0])
		finval = finval[1:]
	}
}
1 Like

My two cents.
check this article:

Or you can print the status of the code:


package main

import "fmt"

func main() {
	fmt.Printf("i \t lenfin \t len(finval) \t finval\n")
	main1()
	fmt.Println("-------------------------------")
	fmt.Printf("i \t lenfin \t len(finval) \t finval\n")
	main2()
}

func main1() {
	var finval []int = []int{1, 2, 3, 4, 5, 6, 7}
	var lenfin = len(finval)
	for i := 0; i < lenfin; i++ {
		//		fmt.Println(i, ":", finval[0])
		finval = finval[1:]
		printStatus(i, lenfin, len(finval), finval)
	}
}

func main2() {
	var finval []int = []int{1, 2, 3, 4, 5, 6, 7}
	for i := 0; i < len(finval); i++ {
		//		fmt.Println(i, ":", finval[0])
		finval = finval[1:]
		printStatus(i, len(finval), len(finval), finval)
	}
}

func printStatus(pos int, lenfin, size int, currentSlice []int) {
	fmt.Printf("%d \t %d \t \t %d \t \t %+v\n", pos, lenfin, size, currentSlice)
}