I am having a hard time learning how to loop through a string in Go to do some stuff (specifically, to separate words than contain vowels).
I wrote this code snippet: https://play.golang.org/p/zgDtOyq6qf.
Here is the error I’m getting when running it:
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. I cannot figure out how to solve this issue. Can someone please suggest something?
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
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
}