恐慌:运行时错误:索引超出范围但数组的长度不为空

时间:2016-08-24 09:05:16

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

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

我写了这段代码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

我在这个论坛上搜索过,有人说这是由于阵列的长度,但事实并非如此。我无法弄清楚如何解决这个问题。 有人可以建议吗?感谢

3 个答案:

答案 0 :(得分:2)

首先让我们解释一下:

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

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

Slice internals

  

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

所以result := make([]string, 0, 4)使用[]stringlength = 0分配并初始化capacity = 4类型的对象。
并且result := make([]string, 4, 4)使用[]stringlength = 4分配并初始化capacity = 4类型的对象,该对象等于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]是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])
}

输出:

"", "", "", "" 

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
}

答案 1 :(得分:1)

问题是您正在创建一个长度为0的切片,但最大容量为4,但同时您尝试将一个值分配给第0个零索引创建的切片,通常为空。这就是您收到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

您可以在此处阅读数组切片地图https://blog.golang.org/go-slices-usage-and-internals

答案 2 :(得分:0)

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

myFunc中,您有:

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

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

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

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

您可以详细了解切片如何操作here