【问题标题】:Slice out of bounds using [][]int but works with map[int][]int使用 [][]int 切片越界,但适用于 map[int][]int
【发布时间】:2018-05-19 16:38:01
【问题描述】:

为什么这段代码有效

graph := make(map[int][]int, 0)

graph[0] = append(graph[0], 1)

但是如果你用graph := make([][]int, 0)替换第一行我得到panic: runtime error: index out of range?这很奇怪。

【问题讨论】:

  • 因为 slice 的长度是 0 所以不能追加到它上面
  • @Himanshu 不是追加动态改变切片大小的目的吗?我试过了 graph := [][]int{} 也不管用。
  • 是的,但是你必须先设置它的键,因为它的二维切片就是错误的原因。

标签: go go-map


【解决方案1】:

让我们简化您的代码,让正在发生的事情更加明显 (Playground link):

graph1 := make(map[int]int, 0)
graph2 := make([]int, 0)

x := graph1[0] // Success
y := graph2[0] // Panic

从这里我们看到差异是由于 map[int][]int ——您类型中的第二个数组实际上是无关紧要的。

现在要了解为什么会发生这种情况,我们需要了解 Go 如何处理 map 和 slice 访问。从Go Maps in Action我们了解到:

如果请求的键不存在,我们获取值类型的零值

在您的原始代码中,切片 ([]int) 的零值为 nilappend()nil 作为第一个参数视为空切片。

但是当我们尝试访问空切片的第 0 个元素时,我们会感到恐慌,因为切片是空的。

总而言之,append 和您类型的第二个部分都是您问题中的红鲱鱼。尝试访问切片第一维中不存在的元素时会发生恐慌。

【讨论】:

    【解决方案2】:

    当您在graph := make(map[int][]int, 0) 中创建时,您将内存分配给您的地图,而不是数组。所以你可能只这样做 graph := make(map[int][]int).

    分解你的代码:

    type a []int
    type m map[int]a
    
    func main() {
        fmt.Println("Hello, playground")
    
        //decomping graph := make(map[int][]int, 0)
        graph := make(m)
    
        //map is empty
        fmt.Println(len(graph))
    
        //decomping graph[0] := append(graph[0], 1)
        itm_a := 1
        arr_a := []int{}
    
        //appeding item to "a" type
        arr_a = append(arr_a, itm_a)
    
        //appending array of a to graph
        graph[0] = arr_a
    
        //print graph
        fmt.Println(graph)
    }
    

    playground

    您得到的错误是由概念错误引起的。 当您执行graph := make([][]int, 0) 时,您将内存分配给切片,而不是数组。见https://blog.golang.org/go-slices-usage-and-internals

    所以你可以这样做(反编译解决方案):

    type a []int
    type m []a
    
    func main() {
        fmt.Println("Hello, playground")
    
        //decomping graph := make([][]int, 0)
        //see that you must be set the length
        graph := make(m, 0)
    
        //map is empty
        fmt.Println(len(graph))
    
        //this is incorrect: graph[0] := append(graph[0], 1)
        //this is correct:   graph[0] := append(graph[0], []int{1})
        //see:
        itm_a := 1
        arr_a := []int{}
    
        //appeding item to "a" type
        arr_a = append(arr_a, itm_a)
    
        //appending slice of a to graph (slice)
        graph = append(graph, arr_a)
    
        //print graph
        fmt.Println(graph)
    }
    

    playground

    【讨论】:

      【解决方案3】:

      由于切片长度为0,代码出现混乱。如果你想在切片上附加任何东西,你只需要提供它的长度,如下所示。

      graph := make([][]int, 1)
      fmt.Println(len(graph))
      graph[0] = append(graph[0], 1)
      fmt.Println(graph)
      

      要将数据附加到第一级的切片,请附加到其第一个索引,然后附加到第二级,如下所示。

      graph := make([][]int, 0)
      fmt.Println(len(graph))
      graph = append(graph, []int{1})
      

      查看Playground example

      【讨论】:

        【解决方案4】:

        make(map[int][]int, 0) 创建 map[]int

        通过 Go 的设计,您可以从地图中获取任何元素。如果它不存在,您会收到“零”值,这里是一个空切片。

        graph := make(map[int][]int)
        
        graph[4] = append(graph[4], 1)
        graph[7] = append([]int{}, 1, 2)
        graph[11] = append([]int{1, 2, 3}, 4, 5)
        

        打印它给出了这个切片:

        fmt.Printf("%#v\n", graph)
        
        map[int][]int{
            4:[]int{1},
            7:[]int{1, 2},
            11:[]int{1, 2, 3, 4, 5},
        }
        

        您的第二个示例创建了一个由 []int 切片组成的空切片。切片与地图的工作方式不同,因此索引不存在的元素会让您感到恐慌。

        【讨论】:

          猜你喜欢
          • 2016-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-01
          • 2021-11-18
          • 2022-11-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多