Go “panic: runtime error: index out of range” when the length of array is not null

后端 未结 3 1341
孤街浪徒
孤街浪徒 2021-01-03 03:37

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:

3条回答
  •  一向
    一向 (楼主)
    2021-01-03 04:26

    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
    }
    

提交回复
热议问题