Функция не меняет указатель после возврата - PullRequest
0 голосов
/ 24 октября 2018

Язык - это «Go» («Golang»).

Функция initApp получает указатель на объект («struct» в Go).Внутри функции я создаю новый указатель объекта и инициализирую значение объекта.Печать и отладчик показывают, что до возврата функции все хорошо.Но после Return указатель, который был аргументом функции, имеет то же пустое значение, что и до вызова функции.

Почему это так?

Код здесь: https://pastebin.com/0Gww2CQC

// ptr.go.

package main

import "fmt"

type ClassX struct {
    Name string
    Age  int
}

func main() {
    var obj *ClassX
    initApp(obj)
    fmt.Println(obj)
    return
}

func initApp(x *ClassX) {
    tmp := NewClassXObject()
    x = tmp
    fmt.Println("tmp:", tmp)
    fmt.Println("x:", x)
}

func NewClassXObject() *ClassX {
    x := new(ClassX)
    x.init()
    return x
}

func (o *ClassX) init() {
    o.Age = 123
    o.Name = "John"
}

Вывод следующий:

tmp: &{John 123} x: &{John 123} <nil>

Спасибо!

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Помните, все в Go передается значением .Когда вы передаете указатель, вы передаете указатель по значению.Ваш аргумент функции - это новая локальная переменная с тем же значением, которое было передано ей вызывающей стороной;т.е. новый указатель, который указывает на то же место в памяти.Итак, ваш код:

func initApp(x *ClassX) {
    tmp := NewClassXObject()
    x = tmp
    fmt.Println("tmp:", tmp)
    fmt.Println("x:", x)
}

Создает новый *ClassX в tmp, затем перезаписывает x новым указателем на новую ячейку памяти, а затем возвращает.Ничто из этого не имеет никакого влияния на область действия вызывающего абонента;указатель, переданный вызывающим абонентом, все еще указывает на тот же адрес памяти, что и раньше.Вы можете изменить значение, на которое указывает x:

func initApp(x *ClassX) {
    tmp := NewClassXObject()
    *x = *tmp
    fmt.Println("tmp:", tmp)
    fmt.Println("x:", x)
}

Теперь у вас есть два указателя на две отдельные области памяти, и вы копируете значение, на которое указывает один, в память, на которое указывает другой, так что они оба указывают на два одинаковых значения в двух разных местах памяти.Это то, что вы должны сделать, если хотите перезаписать значение, на которое указывает вызывающий объект.

Однако, поскольку это создает новое значение, вероятно, вам нужно не перезаписать значение вызывающего, авернуть новое значение.Использование указателей в качестве «выходных параметров» очень и очень ограничено в Go;поскольку вы можете возвращать несколько значений, вы почти всегда просто хотите вернуть значение, а не обновлять аргумент указателя:

func initApp() *ClassX {
    return NewClassXObject()
}

func main() {
    var obj = initApp()
    fmt.Println(obj)
}
0 голосов
/ 24 октября 2018

Я нашел решение.

Кажется, что Go Garbage Collector не понимает, что я делаю, и очищает память.

Это решение помогает:

func main() {
    var obj *ClassX
    obj = new(ClassX) //!
    initApp(obj)
    fmt.Println(obj)
    return
}

func initApp(x *ClassX) {
    tmp := NewClassXObject()
    *x = *tmp //!
    fmt.Println("tmp:", tmp)
    fmt.Println("x:", x)
}

Но это безобразно и глупо.Может быть, есть более элегантный путь?

...