i am having a hard time learning how to loop through a string in Golang
to do some stuff(separate words than contain vowels).
I wrote this code snippet https://play.golang.org/p/zgDtOyq6qf
Here is the error :
panic: runtime error: index out of range
goroutine 1 [running]:
panic(0x1045a0, 0x1040a010)
/usr/local/go/src/runtime/panic.go:500 +0x720
main.myFunc(0x114130, 0x4, 0x0, 0x0, 0x0, 0x3ba3)
/tmp/sandbox960520145/main.go:19 +0x1a0
main.main()
/tmp/sandbox960520145/main.go:10 +0x40
I searched in this forum and someone said that it's due to the length of the array but it's not the case here. Ican't figure out how to solve this.
Can someone please suggest anything? Thanks
The issue is that you are creating a slice with length 0
, but with a maximum capacity of 4
, but at the same time you are trying to allocate already a value to the zeroth index of the slice created, which is normally empty. This is why you are receiving the index out of range error
.
result := make([]string, 0, 4)
fmt.Println(len(result)) //panic: runtime error: index out of range
You can change this code with:
result := make([]string, 4)
which means the capacity will be the same length as the slice length.
fmt.Println(cap(result)) // 4
fmt.Println(len(result)) // 4
You can read about arrays, slices and maps here: https://blog.golang.org/go-slices-usage-and-internals
First let's explain:
result := make([]string, 0, 4)
The make built-in function allocates and initializes an object of type []string
call it Slice
of string
Slice internals:
A slice is a descriptor of an array segment. It consists of a pointer
to the array, the length of the segment, and its capacity (the maximum
length of the segment).
So result := make([]string, 0, 4)
allocates and initializes an object of type []string
with length = 0
and capacity = 4
.
And result := make([]string, 4, 4)
allocates and initializes an object of type []string
with length = 4
and capacity = 4
, which is equal to result := make([]string, 4)
.
Now what is the difference between result := make([]string, 0, 4)
and result := make([]string, 4)
:
With result := make([]string, 0, 4)
the underlying array of this Slice is empty meaning using result[0]
will panic: runtime error: index out of range.
With result := make([]string, 4)
the underlying array of this Slice has 4 string
elements, meaning using result[0]
, result[1]
, result[2]
, result[3]
is OK:
package main
import "fmt"
func main() {
result := make([]string, 4)
fmt.Printf("%q, %q, %q, %q \n", result[0], result[1], result[2], result[3])
}
output:
"", "", "", ""
And result := make([]string, 4)
is equal to result := []string{"", "", "", ""}
meaning this code:
package main
import "fmt"
func main() {
result := []string{"", "", "", ""}
fmt.Printf("%q, %q, %q, %q \n", result[0], result[1], result[2], result[3])
}
output is the same as above code:
"", "", "", ""
The append built-in function
appends elements to the end of a slice. If it has sufficient capacity,
the destination is resliced to accommodate the new elements. If it
does not, a new underlying array will be allocated. Append returns the
updated slice. It is therefore necessary to store the result of
append, often in the variable holding the slice itself:
slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)
As a special case, it is legal to append a string to a byte slice,
like this:
slice = append([]byte("hello "), "world"...)
Now in your code inside function myFunc
after result := make([]string, 0, 4)
, you may use append
, like this working code (The Go Playground):
package main
import (
"fmt"
"strings"
)
func main() {
strs := strings.Fields("Political srt")
fmt.Println(len(strs)) // It's not empty so why index out of range
fmt.Println(strs, strs[0], strs[1])
fmt.Println(strings.ContainsAny(strs[0], "eaiuo"))
fmt.Println(myFunc("Political srt"))
}
func myFunc(input string) []string {
strs := strings.Fields(input)
result := make([]string, 0, 4)
for i := 0; i < len(strs); i++ {
if strings.ContainsAny(strs[i], "eaiu") {
result = append(result, strs[i])
} else {
result = append(result, strs[i])
}
}
return result
}
You may simplify that code, like this working code (The Go Playground):
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(myFunc("Political srt"))
}
func myFunc(input string) []string {
strs := strings.Fields(input)
result := make([]string, 0, 4)
for _, s := range strs {
if strings.ContainsAny(s, "eaiu") {
result = append(result, s)
}
}
return result
}
Index out of range error is appearing because you are not initializing the result
array with sufficient length.
In myFunc
, you have:
result := make([]string, 0, 4)
This creates a slice of strings which has an underlying array of length 4, but since you have declared slice length to be 0, none of the elements from underlying array are accessible to the slice. So even result[0]
is out of range of the available indices.
To fix this, simply supply a sufficiently large length parameter to make
:
result := make([]string, 4, 4)
You can read more about how slices operate here.