Вырезать из границ, используя [][]int, но работает с картой [int][]int

Почему этот код работает

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

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

Но если вы замените первую строку на graph := make([][]int, 0) я получил panic: runtime error: index out of range? Это очень странно.

4 ответа

Решение

Когда вы делаете в 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)
}

Вижу на детской площадке.

Полученная вами ошибка вызвана концептуальной ошибкой. Когда вы делаете 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)
}

Смотри в детскую площадку

Давайте упростим ваш код, чтобы сделать его более понятным ( ссылка на игровую площадку):

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

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

Отсюда видно, что разница обусловлена map[int] против []int - второй массив в вашем типе на самом деле не имеет значения.

Теперь, чтобы понять, почему это происходит, нам нужно понять, как Go обрабатывает доступ к карте и слайсу. Из Go Maps in Action мы узнаем:

Если запрошенный ключ не существует, мы получаем нулевое значение типа значения.

В исходном коде нулевое значение для среза ([]int), является nil, а также append() лечит nil в качестве первого аргумента в качестве пустого фрагмента.

Но когда мы пытаемся получить доступ к 0-му элементу пустого слайса, мы получаем панику, потому что слайс пуст.

В итоге, append и второй кусочек вашего типа - красная сельдь в вашем вопросе. Паника возникает при попытке доступа к несуществующему элементу в первом измерении вашего среза.

Код паникует из-за длины фрагмента 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})

Проверьте пример детской площадки

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 дольки. Срезы работают не так, как карты, поэтому индексирование несуществующего элемента вызовет панику.

Другие вопросы по тегам