Как на самом деле работает эта «общая идиома»?

#go #variable-assignment #slice #scanline

# #Вперед #присвоение переменной #срез #scanline

Вопрос:

Просматриваю документацию для 2D-фрагментов golang и не могу понять синтаксис, используемый в последнем примере:

 func main() {
    XSize := 5
    YSize := 5

    // Allocate the top-level slice, the same as before.
    picture := make([][]uint8, YSize) // One row per unit of y.

    // Allocate one large slice to hold all the pixels.
    pixels := make([]uint8, XSize*YSize) // Has type []uint8 even though picture is [][]uint8.

    // Loop over the rows, slicing each row from the front of the remaining pixe ls slice.
    for i := range picture {
        picture[i], pixels = pixels[:XSize], pixels[XSize:]
    }
}
 

Я нашел запрос на изменение, в котором это было добавлено в документы, и у автора изменений был этот обычный / простой для понимания код:

 // Loop over the rows, slicing each row.
for i := range picture {
     picture[i] = pixels[i*XSize:(i 1)*XSize]
 

Однако есть следующий комментарий:

хорошо. другая распространенная идиома — избегать математики:

picture[i], pixels = pixels[:XSize], pixels[XSize:]

Мой вопрос в том, как вышеупомянутое достигает того же, что и метод!»избегать математики»? Некоторые документы о том, что происходит, были бы замечательными.

Ответ №1:

Это:

 picture[i], pixels = pixels[:XSize], pixels[XSize:]
 

Это назначение кортежа. Он присваивает значение picture[i] и значение pixels . Значения, назначенные по порядку, являются pixels[:XSize] и pixels[XSize:] .

Назначение выполняется в два этапа. Во-первых, операнды индексных выражений и косвенных указателей (включая неявные косвенные указатели в селекторах) слева и выражения справа вычисляются в обычном порядке. Во-вторых, назначения выполняются в порядке слева направо.

Здесь происходит то, что при запуске цикла ( i = 0 ) первому элементу picture (первой строке) присваивается значение среза, являющееся первыми XSize элементами pixels , и pixels срез повторно используется, поэтому его первым элементом будет XSize th element 1 .

Итак, на следующей итерации picture[i] будет 2-й элемент в picture (2-й строке), и опять же, первые XSize элементы из pixels будут установлены для него как срез. Но поскольку на предыдущей итерации мы изменили pixels , на каждой итерации его первыми XSize элементами будут последующие строки.

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

1. Благоговейный трепет. Полностью имеет смысл. (picture[i], pixels) = (pixels[:XSize], pixels[XSize:]) . Просто не видел этого таким образом.

Ответ №2:

Этот пример назначения кортежа можно переписать следующим образом:

 for i := range picture {
    picture[i]= pixels[:XSize]
    pixels = pixels[XSize:]
}
 

Теперь легче увидеть, что изображение — это первые элементы XSize в пикселях.

И эти пиксели изменяются в каждом цикле и отбрасывают свои первые элементы XSize.