Pointers 将'slice'追加到后指向'slice'元素的指针的行为

Pointers 将'slice'追加到后指向'slice'元素的指针的行为,pointers,go,slice,Pointers,Go,Slice,我想知道slice被附加到slice之后,指向slice元素的指针的行为是什么,例如: package main import "fmt" func main() { my_slice := []int {3} silly_ptr := &my_slice[0] // Do we know that silly_ptr points to value equal 3 // all the time? (If we don't explicitly c

我想知道
slice
被附加到
slice
之后,指向
slice
元素的指针的行为是什么,例如:

package main

import "fmt"

func main() {
    my_slice := []int {3}

    silly_ptr := &my_slice[0]
    // Do we know that silly_ptr points to value equal 3
    // all the time? (If we don't explicitly change it).

    fmt.Printf("%p\n", silly_ptr)
    fmt.Println(*silly_ptr)

    for i := 0; i < 10; i++ {
        my_slice = append(my_slice, i)
    }

    silly_ptr_2 := &my_slice[0]

    fmt.Printf("%p\n", silly_ptr_2)
    fmt.Println(*silly_ptr_2)
}
我知道当附加到动态数组时,在某些点上我们已经重新填充了整个数组,因此原始数组元素的内存地址是不可靠的。就我所知,类似的代码在
c++
中是有效的,但是
spuly\u ptr
可能指向任何东西
rust
不允许对借用的
向量进行变异,因此上述逻辑无法编译


但是去怎么样呢?我知道通过
escape analysis
返回一个指向局部变量的指针是有效的,该变量将在堆上为您创建。我的直觉告诉我,同样的逻辑适用于上述情况。
spuly\u ptr
指向的内存位置将不会重新填充,因此将始终存储
3
(如果我们不明确更改它)。是这样吗?

不,它不会总是存储3

Go具有内存管理功能。只要有一个指向片的底层数组的活动指针,底层数组就会被固定,它就不会被垃圾收集。如果有指向基础数组元素的指针,则可以更改该元素的值。比如说,

package main

import (
    "fmt"
)

func pin() *int {
    s := []int{3}
    fmt.Println(&s[0])
    a := &s[0]
    s = append(s, 7)
    fmt.Println(&s[0])
    return a
}

func main() {
    a := pin()
    fmt.Println(a, *a)
    *a = 42
    fmt.Println(a, *a)
}
package main

import (
    "fmt"
)

func pin() []int {
    s := []int{3}
    fmt.Println(&s[0])
    d := s
    s = append(s, 7)
    fmt.Println(&s[0])
    return d
}

func main() {
    d := pin()
    fmt.Println(&d[0], d)
    d[0] = 42
    fmt.Println(&d[0], d)
}
输出:

0xc82000a340
0xc82000a360
0xc82000a340 3
0xc82000a340 42
0xc82000a340
0xc82000a360
0xc82000a340 [3]
0xc82000a340 [42]
切片描述符包含一个指向底层数组的指针,因此可以看到与切片类似的内容。比如说,

package main

import (
    "fmt"
)

func pin() *int {
    s := []int{3}
    fmt.Println(&s[0])
    a := &s[0]
    s = append(s, 7)
    fmt.Println(&s[0])
    return a
}

func main() {
    a := pin()
    fmt.Println(a, *a)
    *a = 42
    fmt.Println(a, *a)
}
package main

import (
    "fmt"
)

func pin() []int {
    s := []int{3}
    fmt.Println(&s[0])
    d := s
    s = append(s, 7)
    fmt.Println(&s[0])
    return d
}

func main() {
    d := pin()
    fmt.Println(&d[0], d)
    d[0] = 42
    fmt.Println(&d[0], d)
}
输出:

0xc82000a340
0xc82000a360
0xc82000a340 3
0xc82000a340 42
0xc82000a340
0xc82000a360
0xc82000a340 [3]
0xc82000a340 [42]

我应该更清楚,我不想考虑一个显式地改变指针指向的值的情况。但您会说:“只要有一个指向片的底层数组的活动指针,底层数组就被固定,它不会被垃圾收集。”这似乎回答了我的问题:
dully\u ptr
将始终指向等于3的值,除非我们显式更改该值,对吗?你知道关于这个主题有什么好的资源吗?@Akavall:我的回答表明,你可以安全地使用指针来读取和写入元素值。Go垃圾收集项目的文本是:《垃圾收集手册:自动内存管理的艺术》(Chapman&Hall/CRC应用算法和数据结构系列)R.Jones,A.Hosking,E.Moss。