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 вместо одного?
И если да, то лучше ли, чтобы я сначала не сохранил его в переменной?
Ответы
Ответ 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