Почему мое решение неверно для упражнения tour of go slices?

# #go

Вопрос:

Я изучаю golang и пытаюсь закончить tour of go. Я застрял в упражнении для срезов. Скопируйте вопрос и мое решение здесь. Может ли кто-нибудь критиковать это и сказать мне, что я здесь делаю неправильно?

Вопрос:

 Implement Pic. It should return a slice of length dy, each element of which is a slice of dx 8-bit 
unsigned integers. When you run the program, it will display your picture,
interpreting the integers as grayscale (well, bluescale) values.

The choice of image is up to you. Interesting functions include (x y)/2, x*y, and x^y.

(You need to use a loop to allocate each []uint8 inside the [][]uint8.)

(Use uint8(intValue) to convert between types.)
 

Мое решение:

 package main

import "golang.org/x/tour/pic"

func Pic(dx, dy int) [][]uint8 {
    ans := make([][]uint8, dy)
    for i:=0; i< dy; i   {
        slice := make([]uint8, dx)
        for j := 0; j<dx;j  {
            slice = append(slice, uint8((i j)/2))
        }
        ans = append(ans,slice)
    }
    return ans
}

func main() {
    pic.Show(Pic)
}

 

При запуске я получаю сообщение об ошибке:

паника: ошибка времени выполнения: индекс выходит за пределы диапазона [0] с длиной 0

Я не уверен, что я здесь делаю не так. Кроме того, почему в упражнении передается функция? Это предназначено?

Комментарии:

1. Я не сразу вижу что-то, что могло бы привести к выходу индекса за пределы диапазона. Можете ли вы сказать нам, в какой строке go паникует? Кроме того, вы не должны использовать append , когда вы уже инициализировали свой массив с требуемой длиной. Используйте slice[j] = uint((i j)/2) and ans[i] = slice вместо ваших вызовов append.

2. О, и да, передача функции используется довольно часто. Например, при определении функций AWS lambda.

3. вставка всего вывода из консоли ниже: panic: runtime error: index out of range [0] with length 0 goroutine 1 [running]: golang.org/x/tour/pic.Show(0xc0000001a0) /tmp/gopath4212376619/pkg/mod/golang.org/x/tour@v0.0.0-20201207214521-004403599411/pic/pic.go:36 0x153 main.main() /tmp/sandbox1296331084/prog.go:18 0x25

Ответ №1:

Хорошо, я понял. Как я уже сказал в своем комментарии, вы должны заменить свои вызовы append на slice[j] = uint((i j)/2) and ans[i] = slice .

Упражнение вызывает вашу функцию с 256×256. Вы создаете фрагмент длиной 256, а затем добавляете другие фрагменты 256 раз, в результате чего получается фрагмент длиной 512 ans . Первые 256 записей пусты, поскольку append добавляется slice в конце. Поэтому, когда библиотека pic выполняет итерацию ваших данных, она пытается получить доступ к пустому фрагменту.

Обновление: еще один способ исправить алгоритм — инициализировать срезы длиной 0. Итак, редактирование

ans := make([][]uint8, 0) и slice := make([]uint8, 0)

также должно давать правильные результаты.

Комментарии:

1. Насколько я понимаю, проблемная часть заключается в том, что при инициализации среза я передаю аргумент длины. Насколько я понимаю, аргумент length на самом деле просто определял длину и не заполнял пустые значения. Но, похоже, это так. Я создал ссылку go playground для подкрепления этого здесь . Итак, вместо ans := make([][]uint8, dy) того, чтобы я должен был сделать ans := make([][]uint8, 0) .

2. Можете ли вы обновить свой ответ, чтобы четко объяснить это.

3.Точно @vector-hector 🙂 @chain_of_dogs pkg.go.dev/builtin#добавить 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. ...

4. @chain_of_dogs Да, это тоже сработало бы. Следовательно, я обновил свой ответ. Однако, насколько я понимаю, моя первая версия будет предпочтительной, потому что go знает, сколько места нужно выделить при его инициализации. Используя append, он пытается перераспределить пространство, если оно заканчивается.