Подтвердить что ты не робот

Go: Я создаю слишком много значений?

Если у меня есть такая структура, как

type myStruct struct {
    mystring string
    myint int
}

и если у меня есть функция, которая возвращает новый myStruct, подобный этому

func New() myStruct {
    s := myStruct{}

    s.mystring = "string"
    s.myint = 1

    return s
}

Поскольку я сначала сохраняю его в переменной "s" перед его возвратом, является ли моя функция фактически делать 2 значения myStruct вместо одного?

И если да, то лучше ли, чтобы я сначала не сохранил его в переменной?

4b9b3361

Ответ 1

Оператор return вернет копию значения объекта myStruct. Если это небольшой объект, тогда это нормально.

Если вы хотите, чтобы вызывающий объект мог изменять этот объект, а структура будет иметь методы, которые используют указатель в качестве получателя, тогда имеет смысл возвращать указатель на вашу структуру:

func New() *myStruct {
    s := myStruct{}

    s.mystring = "string"
    s.myint = 1

    return &s
}

Вы можете увидеть, что копия происходит, когда вы сравниваете адрес памяти значений с типами возвращаемых указателей: http://play.golang.org/p/sj6mivYSHg

package main

import (
    "fmt"
)

type myStruct struct {
    mystring string
    myint    int
}

func NewObj() myStruct {
    s := myStruct{}
    fmt.Printf("%p\n", &s)

    return s
}

func NewPtr() *myStruct {
    s := &myStruct{}
    fmt.Printf("%p\n",s)
    return s
}

func main() {

    o := NewObj()
    fmt.Printf("%p\n",&o)

    p := NewPtr()
    fmt.Printf("%p\n",p)
}


0xf8400235a0 // obj inside NewObj()
0xf840023580 // obj returned to caller
0xf840023640 // ptr inside of NewPtr()
0xf840023640 // ptr returned to caller

Ответ 2

Я определенно не эксперт Go (или даже новичок:)), но, как упоминал @max.haredoom, вы можете выделить переменные в самой функции. Таким образом, вы также можете опустить s в return:

package main

import "fmt"

type myStruct struct {
    mystring string
    myint    int
}

func New() (s myStruct) {
    s.mystring = "string"
    s.myint = 1

    return
}

func main() {
    r := New()
    fmt.Println(r)
}

// Outputs {string 1}

В примерах, которые я встретил в "Эффективный путь" , это, по-видимому, самый распространенный способ делать вещи такого характера, но опять же, я определенно не авторитет в этом вопросе (и буду искать дополнительную информацию о фактической производительности).

Ответ 3

Я думаю, что нашел ответ, используя defer.

Я обновил функцию так, чтобы отложенная модификация значения myStruct. Это означает, что это произойдет после возвращения, но до того, как оно будет получено на другом конце.

Когда я это делаю, структура, полученная вызывающим абонентом, не показывает обновленное значение, поэтому оно выглядит так, как будто я действительно возвращаю копию.

func New() myStruct {
    s := myStruct{}

    defer func() {
        s.mystring = "new value" // defer an update to the value
    }()

    s.mystring = "string"
    s.myint = 1

    return s
}

func main() {

    b := New()

    fmt.Println(b) // still shows the original value
}

http://play.golang.org/p/WWQi8HpDny