我制作了一个程序,以了解有关数组和切片的更多信息,在此示例中,我只是更改了固定位置的值。当我查看指针地址时,每次更改后都会更改。为什么会这样?
来源:
func main() {
tstSlice2()
}
func tstSlice2() {
var meuSlice = make([]int, 1, 2)
meuSlice[0] = 1
printSlice(meuSlice, "meuSlice")
meuSlice[0] = 2
printSlice(meuSlice, "meuSlice")
meuSlice[0] = 3
printSlice(meuSlice, "meuSlice")
}
func printSlice(meuSlice []int, sliceName string) {
fmt.Printf("%v> %v - %v - %v - %p \n", sliceName, len(meuSlice), cap(meuSlice), meuSlice, &meuSlice)
}
输出:
▶ go run .\src\array_e_slices\slice.go
meuSlice> 1 - 2 - [1] - 0xc0420503e0
meuSlice> 1 - 2 - [2] - 0xc042050440
meuSlice> 1 - 2 - [3] - 0xc042050480
答案 0 :(得分:1)
因为您每次都要传递切片的副本。未复制基础数组时,切片会复制。我认为原则上您可以将slice视为结构:
type Slice struct {
pointer PointerToArray
StartIndex int
Len int
}
下面的代码应打印相同的指针:
func tstSlice2() {
var meuSlice = make([]int, 1, 2)
meuSlice[0] = 1
printSlice(&meuSlice, "meuSlice")
meuSlice[0] = 2
printSlice(&meuSlice, "meuSlice")
meuSlice[0] = 3
printSlice(&meuSlice, "meuSlice")
}
func printSlice(meuSlice *[]int, sliceName string) {
fmt.Printf("%v> %v - %v - %v - %p \n", sliceName, len(*meuSlice), cap(*meuSlice), *meuSlice, meuSlice)
}
答案 1 :(得分:1)
您在printSlice
函数中传递的不是切片,而是切片标头,它描述了基础数组。当您将切片传递给函数时,将生成标头的副本,因为在运行中元素总是 passed by value。
在函数调用中,函数值和参数在 通常的顺序。评估之后,调用的参数 通过值传递给函数,被调用函数开始 执行。函数的返回参数按值传递 函数返回时返回到调用函数。
如果要检查此标头中的内容,请检查reflect.SliceHeader的类型。
代码示例:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
tstSlice2()
}
func tstSlice2() {
var meuSlice = make([]int, 1, 2)
meuSlice[0] = 1
printSlice(meuSlice, "meuSlice")
meuSlice[0] = 2
printSlice(meuSlice, "meuSlice")
meuSlice[0] = 3
printSlice(meuSlice, "meuSlice")
}
func printSlice(meuSlice []int, sliceName string) {
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&meuSlice))
fmt.Printf("%v> %v - %v - %v - %p - array: %v\n", sliceName, len(meuSlice), cap(meuSlice), meuSlice, &meuSlice, hdr.Data)
}
输出:
meuSlice> 1 - 2 - [1] - 0xc42000a060 - array: 842350559504
meuSlice> 1 - 2 - [2] - 0xc42000a0a0 - array: 842350559504
meuSlice> 1 - 2 - [3] - 0xc42000a0e0 - array: 842350559504
去游乐场: https://play.golang.org/p/x2OoIHgU9St
您可以在博客文章Go Slices: usage and internals(尤其是Slice内部构件部分)中找到更多信息
切片是数组段的描述符。它由一个指针组成 到数组,段的长度及其容量(最大 段的长度。
传递给函数的是此结构的值,而不是基础数组本身。为此,您需要使用*[]int
参数,如其他答案中所述。
答案 2 :(得分:0)
切片值包含一个指向后备数组,长度和容量的指针。有关所有详细信息,请参见Go Slices: usage and internals。
程序将打印切片menuSlice
的地址。每次调用的参数地址都不相同。
看来您的目标是打印切片的后备阵列的地址。为此,请打印第一个slice元素的地址。第一个元素的地址与整个后备阵列的地址相同。
func printSlice(meuSlice []int, sliceName string) {
fmt.Printf("%v> %v - %v - %v - %p \n", sliceName, len(meuSlice), cap(meuSlice), meuSlice, &meuSlice[0])
}
该程序的输出为:
meuSlice> 1 - 2 - [1] - 0x10414020
meuSlice> 1 - 2 - [2] - 0x10414020
meuSlice> 1 - 2 - [3] - 0x10414020
上面的代码对nil和零长度切片感到恐慌。为了避免出现紧急情况,请在获取第一个元素的地址之前检查切片的长度:
func printSlice(meuSlice []int, sliceName string) {
var p *int
if len(meuSlice) > 0 {
p = &meuSlice[0]
}
fmt.Printf("%v> %v - %v - %v - %p \n", sliceName, len(meuSlice), cap(meuSlice), meuSlice, p)
}