Разыменование указателей в срезе, похоже, не дает начального значения, из которого был создан указатель

Мне нужно создать фрагмент указателей для проекта Go, над которым я работаю, который ссылается на элементы в фрагменте. Ожидаемым поведением было бы то, что я мог бы изменить один из разыменованных элементов в срезе указателей, и это изменило бы исходный элемент в обычном списке, на который он указывает. Ожидается, что изменение исходных элементов также будет отображаться как новое значение при разыменовании указателей в срезе. Однако ни одно из этих действий, похоже, не работает.

Вот демо-код, который я написал, чтобы воспроизвести это.

package main

import "fmt"

func main() {
    var x []int = []int{5,4,3,2,1}
    var y *[]int = &x

    var g []*int
    for _, x := range x {
        g = append(g, &x)
    }

    fmt.Println("x, y, g, *g  = ")
    fmt.Println(x)
    fmt.Println(y)
    fmt.Println(g)
    printPtr(g)
    fmt.Println()
    fmt.Println()

    fmt.Println("Setting *g[0] to 10")
    *g[0] = 10
    
    fmt.Println("*g  = ")
    printPtr(g)
    fmt.Println()
    fmt.Println()

    fmt.Println("Setting x[1] to 17")
    x[1] = 17

    fmt.Println("x, y, *g  = ")
    fmt.Println(x)
    fmt.Println(y)
    printPtr(g)
    fmt.Println()
}

func printPtr(i []*int) {
    for _, v := range i {
        fmt.Print(*v)
        fmt.Print(" ")
    }
}

Этот код печатает:

x, y, g, *g =
[5 4 3 2 1]
&[5 4 3 2 1]
[0x140000a6018 0x140000a6020 0x140000a6028 0x140000a6030 0x140000a6038]
5 4 3 2 1 

Setting *g[0] to 10
*g =
10 4 3 2 1 

Setting x[1] to 17
x, y, *g =
[5 17 3 2 1]
&[5 17 3 2 1]
10 4 3 2 1 

Кажется, что эти два куска каким-то образом не связаны. Что именно здесь идет не так?

(p.s. Мне нужен фрагмент указателей вместо указателя на фрагмент по странным конкретным причинам в моем проекте, в том числе из-за того, что фрагмент указателей и обычный фрагмент могут быть разной длины. Если нет способа добиться этого, я конечно, я мог бы использовать другой метод, однако поначалу он показался самым простым)

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
0
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Выражение диапазона _, x := range x объявляет новую переменную x, ограниченную областью действия цикла. Элемент среза присваивается x на каждой итерации цикла. Петля

for _, x := range x {
    g = append(g, &x)
}

добавляет адрес переменной цикла x к срезу g.

Используйте этот код, чтобы добавить адрес элемента среза к g:

for i := range x {
    g = append(g, &x[i])
}

Примечание. Переменная x, объявленная в цикле вопроса, затеняет переменную среза x. Слежка не является причиной проблемы, а является плохой практикой.

Другие вопросы по теме