我正在修改矩阵的周长值,然后尝试递归到内部值。我希望我能用像matrix[1:3][1:3]
这样的东西来访问内部值。事实并非如此,而且我对Go处理顺序括号的基本逻辑有点迷失。
package main
import (
"fmt"
)
var m = [][]int{
[]int{0, 1, 2, 3},
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
[]int{12, 13, 14, 15},
}
我试图访问上面矩阵中的值5,6,9,10,即“内部”矩阵。
func main() {
inner := m[1:3][1:3]
fmt.Printf("%#v\n", inner)
// Expected Output: [][]int{
// []int{5, 6},
// []int{9, 10}
// }
// Actual Ouput: [][]int{
// []int{8, 9, 10, 11},
// []int{12, 13, 14, 15}
// }
inner = m[1:3]
fmt.Printf("%#v\n", inner)
// Output:
// [][]int{
// []int{4, 5, 6, 7},
// []int{8, 9, 10, 11}
// }
inner = innerMatrix(m)
fmt.Printf("%#v\n", inner)
// [][]int{
// []int{5, 6},
// []int{9, 10}
}
func innerMatrix(m [][]int) (inner [][]int) {
innerRows := m[1:3]
for _, row := range innerRows {
inner = append(inner, row[1:3])
}
return
}
函数innerMatrix能够产生我期望的输出。我迷失了为什么(1)m[1:3][1:3]
没有相同的效果,(2)它似乎转化为m[2:4]
。这是怎么回事?
在Go中创建子切片时,您可以再次将该子切片增加回原始切片的容量,例如:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
b := a[1:3]
fmt.Printf("a[1:3]: %v\n", b)
c := b[1:3]
fmt.Printf("b[1:3]: %v\n", c)
}
哪个输出:
a[1:3]: [2 3]
b[1:3]: [3 4]
请注意,b
只有两个元素,但我们允许创建第二个和第三个元素的切片,因为切片的容量是一个子切片足够大,并且所有切片共享相同的底层数组。请参阅this page上“切片内部”一节中的最后一个示例
那么在你的情况下发生的是m[1:3]
相当于:
var m1 = [][]int{
[]int{4, 5, 6, 7}, // second element of m
[]int{8, 9, 10, 11}, // third element of m
}
因此,m[1:3][1:3]
相当于m1[1:3]
,相当于:
var m2 = [][]int{
[]int{8, 9, 10, 11}, // second element of m1
[]int{12, 13, 14, 15}, // "third" element of m1
}
出现“第三”元素只是因为m
的容量足以容纳它,并且确实包含它。如果m
只有三个元素,这会引起恐慌。
换句话说,m[1:3][1:3]
在这里完全等同于m[2:4]
,因为m[1:3][1:3]
为你提供了m[1:3]
的第二和第三个元素。使用图表可能更容易理解:
m : []int{1, 2, 3, 4}
m[1:3] : []int{ 2, 3 }
m[1:3][1:3] : []int{ 3, 4}
m[2:4] : []int{ 3, 4}
作为过度简化,你可以想象方括号给出了它们左边的任何东西所要求的元素,所以这是一个有点极端的例子:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
b := a[1:5]
fmt.Printf("b: %v, a[1:5] : %v\n",
b, a[1:5])
c := b[1:4]
fmt.Printf("c: %v , a[1:5][1:4] : %v\n",
c, a[1:5][1:4])
d := c[1:3]
fmt.Printf("d: %v , a[1:5][1:4][1:3] : %v\n",
d, a[1:5][1:4][1:3])
e := d[1:2]
fmt.Printf("e: %v , a[1:5][1:4][1:3][1:2]: %v\n",
e, a[1:5][1:4][1:3][1:2])
}
哪个输出:
b: [2 3 4 5], a[1:5] : [2 3 4 5]
c: [3 4 5] , a[1:5][1:4] : [3 4 5]
d: [4 5] , a[1:5][1:4][1:3] : [4 5]
e: [5] , a[1:5][1:4][1:3][1:2]: [5]
这是你的数据:
var m = [][]int{
[]int{0, 1, 2, 3},
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
[]int{12, 13, 14, 15},
}
首先你问内在的是什么:= m [1:3] [1:3]?
好吧,一次取一个,m [1:3]是你在抓取元素1到3而不包括3时得到的子片。那就是元素1和2.元素0是[] int {0,1,2, 3},元素1是[] int {4,5,6,7},元素2是[] int {8,9,10,11},
所以m [1:3]是
[][]int{
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
}
现在,为了得到m [1:3] [1:3],我们在这个结果上重复同样的事情。但是,这一次,只有两个要素。我们再次想要元素1和2.我们跳过元素0,即[] int {4,5,6,7}。元素1是[] int {8,9,10,11}。没有元素2.但是,m [1:3]的结果是一个子片段,底层片段有一个额外的元素。所以通过扩展这个子片我们可以再次获得该元素,那就是hiddent元素2,它是[] int {12,13,14,15}。所以m [1:3] [1:3]是
[][]int{
[]int{8, 9, 10, 11},
[[]int{12, 13, 14, 15},
}
最后,你想知道为什么func innerMatrix的工作方式不同?它首先产生m [1:3]
[][]int{
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
}
然后代码不会以m [1:3] [1:3]是两个连续的子句相同的方式获取另一个子片段。相反,您可以获取切片中的每个元素并从每个元素中获取子切片。第一次通过你从[] int {4,5,6,7}中获取子句[1:3]。结果是
[]int{5, 6}
第二次通过你在第二个元素[] int {8,9,10,11}上做同样的事情
[]int{9, 10}
最后,每次通过你将结果附加到结果切片,所以你将[] int {5,6}追加到[],给[] [] {int {5,6}},然后你追加[] int {9,10}给
[][]{int{5, 6}, []int{9, 10} }