【问题标题】:Go “panic: runtime error: index out of range” when the length of array is not null当数组的长度不为空时,出现“恐慌:运行时错误:索引超出范围”
【发布时间】:2016-12-31 07:56:47
【问题描述】:

我很难学习如何在 Go 中循环一个字符串来做一些事情(特别是分隔单词而不是包含元音)。

我写了这段代码 sn-p:https://play.golang.org/p/zgDtOyq6qf.

这是我在运行它时遇到的错误:

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

我在这个论坛上搜了一下,有人说是数组长度的问题,但是这里不是这样的。我无法弄清楚如何解决这个问题。 有人可以提出一些建议吗?

【问题讨论】:

    标签: arrays string go compiler-errors string-length


    【解决方案1】:

    首先解释一下:

    result := make([]string, 0, 4)
    

    make 内置函数分配并初始化一个 []string 类型的对象,将其称为 Slicestring

    Slice internals

    切片是数组段的描述符。它由一个指针组成 到数组,段的长度,以及它的容量(最大 段的长度)。

    所以result := make([]string, 0, 4) 使用length = 0capacity = 4 分配并初始化[]string 类型的对象。
    result := make([]string, 4, 4)length = 4capacity = 4分配和初始化[]string类型的对象,等于result := make([]string, 4)

    现在result := make([]string, 0, 4)result := make([]string, 4)有什么区别:

    使用result := make([]string, 0, 4),这个 Slice 的底层数组是空的,这意味着使用 result[0] 会恐慌:运行时错误:索引超出范围。

    使用result := make([]string, 4),这个Slice的底层数组有4个string元素,意思是使用result[0]result[1]result[2]result[3]是可以的:

    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])
    }
    

    输出:

    "", "", "", "" 
    

    result := make([]string, 4) 等于result := []string{"", "", "", ""} 意思是这个代码:

    package main
    
    import "fmt"
    
    func main() {
        result := []string{"", "", "", ""}
        fmt.Printf("%q, %q, %q, %q \n", result[0], result[1], result[2], result[3])
    }
    

    输出和上面的代码一样:

    "", "", "", "" 
    

    append 内置函数 将元素附加到切片的末尾。如果容量足够, 目的地被重新分割以适应新元素。如果它 没有,将分配一个新的底层数组。追加返回 更新切片。因此有必要存储结果 附加,通常在保存切片本身的变量中:

    slice = append(slice, elem1, elem2)
    slice = append(slice, anotherSlice...)
    

    作为一种特殊情况,将字符串附加到字节切片是合法的, 像这样:

    slice = append([]byte("hello "), "world"...)
    

    现在在你的函数 myFunc 内部的代码中,在 result := make([]string, 0, 4) 之后,你可以使用 append,就像这个工作代码 (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
    }
    

    您可以简化该代码,例如这个工作代码 (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
    }
    

    【讨论】:

    • @jiji 我希望这会有所帮助。
    • 感谢您的回答和对append 的澄清。我认为在我的情况下,不使用附加功能会更有用,因为我想使用相同的数组进行一些排序,而不是仅仅在数组的末尾添加。
    【解决方案2】:

    问题是您正在创建一个长度为0 的切片,但最大容量为4,但同时您正试图为创建的切片的第零个索引分配一个值,通常是空的。这就是您收到index out of range error 的原因。

    result := make([]string, 0, 4)
    fmt.Println(len(result)) //panic: runtime error: index out of range
    

    您可以使用以下代码更改此代码:

    result := make([]string, 4)
    

    这意味着容量将与切片长度相同。

    fmt.Println(cap(result)) // 4
    fmt.Println(len(result)) // 4
    

    您可以在此处阅读有关 arraysslicesmaps 的信息:https://blog.golang.org/go-slices-usage-and-internals

    【讨论】:

    • 感谢您的回答!不知道slices
    【解决方案3】:

    出现索引超出范围错误,因为您没有以足够的长度初始化 result 数组。

    myFunc,你有:

    result := make([]string, 0, 4)
    

    这将创建一个字符串切片,其基础数组长度为 4,但由于您已将切片长度声明为 0,因此切片无法访问基础数组中的任何元素。所以即使result[0] 也超出了可用索引的范围。

    要解决此问题,只需向make 提供足够大的长度参数:

    result := make([]string, 4, 4)
    

    您可以阅读更多有关切片如何操作的信息here

    【讨论】:

    • 感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2014-11-25
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多