6

Consider the following code which just prints all the ENV vars

package main

import (
    "fmt"
    "os"
)

func main() {
    for i, env := range os.Environ() {
        fmt.Println(i, env)
    }
}

Here, os.Environ() is supposed to return array of strings([] string), to loop over it. I need to to use range keyword & also for loop. Question is:

  1. Why are both for & range required? is it possible to use for loop for this as []string is already an array & we can iterate over arrays right?
  2. In the above code what does range do? and what does for loop does?

Sorry if this question is too stupid, I am just starting with Go

1

3 Answers 3

8

As mentioned in Range Clauses:

A range clause provides a way to iterate over a array, slice, string, map, or channel.

If you want to iterate over an []string, you need range.

A For statement doesn't always use range.

ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .

You have:

  • In its simplest form, a "for" statement specifies the repeated execution of a block as long as a boolean condition evaluates to true

  • A "for" statement with a ForClause is also controlled by its condition, but additionally it may specify an init and a post statement, such as an assignment, an increment or decrement statement

  • A "for" statement with a "range" clause iterates through all entries of an array, slice, string or map, or values received on a channel. For each entry it assigns iteration values to corresponding iteration variables if present and then executes the block.

Sign up to request clarification or add additional context in comments.

2 Comments

It makes sense now, Thank you!
The quotation from golang.org/ref/spec#For_statements was exactly what I was looking for. Thank you!
2

I find the accepted answer slightly confusing as it doesn't directly directly address the questions.

So to answer your questions.

  1. for range is one loop style you can use to access the elements in the environment slice returned from os.Environ(), but as I show below you can use the other for loop style. You will see the differences below.
  2. range in this for loop is the construct you use that will provide a copy and the index for each of the elements in the slice.

To summarize, there are basically two forms of the for loop construct in go (actually 3, but we're only concerned with two here).

One uses the range keyword, and the other does not.

The for ... range version creates a copy of the item in the slice you are iterating over. The other, does not and you must access it by reference.

func main() {
    for i, env := range os.Environ() {
        fmt.Println(i, env)
    }
}

Here is how you would write the for loop without using range construct:

func main() {
    env := os.Environ()
    for i := 0; i < len(env); i++ {
        fmt.Println(i, env[i])
    }
}

I also found a third option which looks tidy and has the same advantage as option 2.

func main() {
    env := os.Environ()
    for i := range env {
        fmt.Println(i, env[i])
    }
}

The first approach is nice and clean, but the second provides better performance because it doesn't do a copy. Both have their place. I would generally use range, but where you need it, the traditional C-like loop is available.

Note: Whenever you are dealing with strings you should always use the range loop as it will return a rune instead of a char. This is particularly important when dealing with internationalisation. See this blog post about string iteration here: Strings, bytes, runes and characters in Go

Comments

1

One notable difference if for range creates copy of each the objects from slice/array. Have a look at following code snippet. https://go.dev/play/p/MHaCXj-Y5WD

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.