这个 "common idiom" 是如何工作的?

How does this "common idiom" actually work?

正在查看 golang's 2D slices 的文档,无法理解上一个示例中使用的语法:

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:]
    }
}

我找到 change request 将其添加到文档中,更改作者有这个正常/易于理解的代码:

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

然而,有如下评论:

fine. another common idiom is to avoid the math:

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

我的问题是上面的方法是如何实现和!"avoid the math"方法一样的?一些关于正在发生的事情的文档会很棒。

这个:

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

是一个元组assignment。它为 picture[i] 分配一个值,为 pixels 分配一个值。按顺序分配的值是 pixels[:XSize]pixels[XSize:].

The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.

这里发生的是,当循环开始时 (i = 0),picture 的第一个元素(第一行)被分配了第一个 XSize 的切片值pixels 中的元素,并且 pixels 切片被重新切片,因此它的第一个元素将是 XSizeth 元素 +1.

所以在下一次迭代中 picture[i] 将是 picture 中的第二个元素(第二行),同样,pixels 中的前 XSize 个元素将被设置为它作为一个切片。但是由于在之前的迭代中我们重新切片 pixels,在每次迭代中它的第一个 XSize 元素将是后续行。

这个元组赋值示例可以重写为:

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

现在更容易看出 图片 是第一个 XSize 像素

并且像素 在每个循环中被修改并丢弃它的第一个XSize项。