Understanding Go’s Range Loop
explores the tension between pushing culinary boundaries and creating a pleasant dining experience.
All perceiving is also thinking, all reasoning is also intuition, all observation is also invention.
— Rudolf Arnheim
Medium Link: Range Notions You Should Know in Golang | by Wesley Wei | Sep, 2024 | Programmer’s Career
Author:Wesley Wei – Medium
Hello, here is Wesley, Today’s article is about range in Go. Without further ado, let’s get started.💪
1.1 for range Overview and Usage
Introduce the basic syntax and usage scenarios of the
for range
loop in Go.
The for range
loop is a very commonly used looping structure in Go, used to iterate over various collection types such as arrays, slices, maps, strings, and channels. The for range
loop can efficiently iterate over these data structures and obtain both the index and value simultaneously.
Basic Syntax
1 | for index, value := range collection {} |
- collection: represents the data structure you want to traverse, such as an array, slice, map, string, or channel(only value).
- index: represents the current element’s index. For maps, the index is the key (key).
- value: represents the current index position’s value.
If you don’t need the index, you can use the underscore (_
) to ignore it:
1 | for _, value := range collection {} |
1.2 for range Usage Scenarios
- Traversing arrays and slices: used to access each element in order.
- Traversing maps: used to access each key-value pair in the map.
- Traversing strings: used to access each character (including Unicode characters) in the string.
- Traversing channels: used to receive data from a channel until it is closed.
Iterating over arrays
An array is a fixed-size sequence, and for range
can be used to iterate over each element in the array.
1 | arr := [5]int{10, 20, 30, 40, 50} |
Note: The length of an array is fixed and will not change during the iteration process.
Iterating over slices
A slice can be thought of as a reference to an array. for range
has similar applications on slices as it does on arrays, but the length of a slice can dynamically change.
1 | slice := []int{100, 200, 300, 400, 500} |
Note: A slice can dynamically expand or shrink, so if the contents of the slice change during iteration, it may affect the loop results.
For more notes on slices, please refer to the article:
Slice Notions You Should Know in Golang | by Wesley Wei | Jul, 2024 | Programmer’s Career
Iterating over maps
A map is a collection of key-value pairs, and for range
can iterate over each key-value pair in the map.
1 | m := map[string]int{"a": 1, "b": 2, "c": 3} |
Note: The iteration order of a map is random and does not guarantee the same order each time it runs.
Iterating over strings
In Go, a string is an immutable sequence of bytes. The for range
statement can be used to iterate over each character in the string, supporting Unicode characters.
1 | str := "Hello, 世界" |
Note:
- When iterating over a string using
for range
, it processes Unicode characters (rune) rather than bytes. This is crucial for handling multi-byte characters (such as Chinese).
Iterating over channels
A channel is a concurrency primitive in Go, used to pass data between goroutines. The for range
statement can be used to iterate over the values received by a channel before it is closed.
1 | ch := make(chan int, 5) |
Note:
- The channel must be closed by the producer when it finishes sending data, or else the
for range
loop will block indefinitely. - The
for range
statement will automatically exit the loop when the channel is closed.
By using for range
to iterate over these data structures, Go can easily handle different types of data.
1.3 for range usage errors
Let’s examine two classic examples that are not intuitive and easy to make mistakes for beginners. These examples illustrate common pitfalls when using range loops in Go.
1 | // pointer example |
In Go versions less than 1.22, the output results like this:
1 | // Pointer example output |
Why is this?
For all range loops in Go, the language will assign a new variable ha
with the original slice or array at compile-time, and copying occurs during the assignment process. Each element will be assigned to a temporary variable. The rough logic is as follows:
1 | ha := a |
And when the Go version is greater than or equal to 1.22, this easily error-prone issue has been “fixed”, with the output result as follows:
1 | // pointer example output |
Specifically, please refer to Fixing For Loops in Go 1.22 - The Go Programming Language. The corresponding relevant logic should be located around GitHub.
1.4 Special Usage of range
The for range
loop can safely delete elements from a map
when iterating over it in Go. This feature is due to the implementation of range
and map
. In many other programming languages, similar operations may cause iterators to become invalid, throw exceptions, or raise undefined behavior.
1 | func main() { |
- In Python, when you try to delete an element from a dictionary (similar to Go’s
map
) while iterating over it, you will usually get aRuntimeError
, because Python’s iterator mechanism does not allow modifying the dictionary during iteration. - In Java, using an
Iterator
to iterate over aHashMap
allows you to remove the current element using theremove()
method. However, if you directly call theMap
‘sremove()
method without using anIterator
, you will get aConcurrentModificationException
.
These two languages want to implement the logic for deleting elements in a map, which is slightly more complicated:
1 | my_dict = {'a': 1, 'b': 2, 'c': 3} |
1 | Map<String, Integer> map = new HashMap<>(); |
Since range
allows deleting elements, adding new elements using the same mechanism is also possible.
Combining the randomness of a map hash table, what will be the output of the following example? Will it go into an infinite loop or not?
1 | func main() { |
References
- Redefining for loop variable semantics · golang/go · Discussion #56010 · GitHub
- Go Range Loop Internals
More Series Articles about You Should Know In Golang:
https://wesley-wei.medium.com/list/you-should-know-in-golang-e9491363cd9a
And I’m Wesley, delighted to share knowledge from the world of programming.
Don’t forget to follow me for more informative content, or feel free to share this with others who may also find it beneficial. it would be a great help to me.
Give me some free applauds, highlights, or replies, and I’ll pay attention to those reactions, which will determine whether or not I continue to post this type of article.
See you in the next article. 👋
中文文章: https://programmerscareer.com/zh-cn/golang-range/
Author: Wesley Wei – Twitter Wesley Wei – Medium
Note: Originally written at https://programmerscareer.com/golang-range/ at 2024-09-01 19:05. If you choose to repost or use this article, please cite the original source.
Comments