果朗切片地址



我有这段代码

package main
import (
    "fmt"
)
func Extend(slice []int, element int) []int {
    n := len(slice)
    if n == cap(slice) {
        // Slice is full; must grow.
        // We double its size and add 1, so if the size is zero we still grow.
        newSlice := make([]int, len(slice), 2*len(slice)+1)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0 : n+1]
    slice[n] = element
    return slice
}
func main() {
    slice := make([]int, 0, 5)
    for i := 0; i < 10; i++ {
        slice = Extend(slice, i)
        fmt.Printf("len=%d cap=%d slice=%vn", len(slice), cap(slice), slice)
        fmt.Println("address of 0th element:", &slice[0])
        fmt.Println("address of slice:", &slice) // why does this print the slice and not its address?
        fmt.Printf("address of slice: %pn", &slice) // why is this different from below? and why does it not change when a new slice is created pointing to a different array?
        fmt.Printf("address of slice: %pnn", slice)
    }
}

游乐场:https://play.golang.org/p/PWMN-i9_z9

我在循环底部的第二个Println上的问题。如果你运行它,你会看到它打印出来&[values…]。为什么它不打印出地址?我知道你可以用Printf和其他方法来做,它很有效,但Println呢?Println与&slice[0]工作正常,它打印地址而不是值,而是带有&切片就像不一样。

我还注意到,当我用&切片,而我只做切片,我得到不同的地址。为什么?以及带有&切片在更改时不会更改(运行它,程序会调整数组的大小并创建一个新的切片)。但是printf(%p,slice)确实发生了变化?

这就是fmt.Println的定义。

发件人https://golang.org/pkg/fmt/#Println:

Println对其操作数使用默认格式进行格式化,并写入标准输出。操作数之间总是添加空格,并附加换行符。它返回写入的字节数以及遇到的任何写入错误。

在该页面的前面,描述了默认格式:

对于复合对象,元素是使用这些规则递归打印的,布局如下:

struct:             {field0 field1 ...}
array, slice:       [elem0 elem1 ...]
maps:               map[key1:value1 key2:value2]
pointer to above:   &{}, &[], &map[]

也许你的问题是"为什么"会是这样。答案是有争议的,但我想这是因为人们认为以这种形式显示数据比原始指针更有用。

您还会问,为什么修改切片不会更改其地址。切片是一种值类型(而不是引用类型),它包含指向底层数组的指针(以及其容量和当前长度)。为切片类型的变量指定新值会覆盖该值,但不会更改其地址。这篇关于切片使用和内部结构的文章是一个很好的参考。