英文:
Go: Am I creating too many values?
问题
如果我有一个像这样的结构体
type myStruct struct {
mystring string
myint int
}
并且如果我有一个返回新的myStruct的函数,像这样
func New() myStruct {
s := myStruct{}
s.mystring = "string"
s.myint = 1
return s
}
因为我在返回之前首先将其存储在"s"变量中,所以我的函数实际上是创建了2个myStruct值而不是一个吗?
如果是这样,那么最好的做法是确保我不首先将其存储在变量中吗?
英文:
If I have a struct like this
type myStruct struct {
mystring string
myint int
}
and if I have a function that returns a new myStruct like this
func New() myStruct {
s := myStruct{}
s.mystring = "string"
s.myint = 1
return s
}
Because I first store it in the "s" variable before returning it, is my function actually making 2 myStruct values instead of one?
And if so, is it then a better practice to make sure I don't first store it in the variable?
答案1
得分: 11
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 // NewObj()内部的对象
0xf840023580 // 返回给调用者的对象
0xf840023640 // NewPtr()内部的指针
0xf840023640 // 返回给调用者的指针
英文:
The return
statement will return a copy of the myStruct
object value. If it is a small object then this is fine.
If you intend for the caller to be able to modify this object, and the struct will have methods that use a pointer as the receiver, then it makes more sense to return a pointer to your struct instead:
func New() *myStruct {
s := myStruct{}
s.mystring = "string"
s.myint = 1
return &s
}
You can see the copy happening when you compare the memory address of value vs pointer return types: 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
得分: 3
我绝对不是Go专家(甚至不是新手 ),但正如@max.haredoom所提到的,你可以在函数签名中分配变量。这样,你也可以省略return
中的s
:
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)
}
// 输出 {string 1}
在我遇到的例子中,在Effective Go中,这似乎是做这种事情的最常见方式,但我绝对不是这个主题的权威(并且将寻找有关实际性能的其他信息)。
英文:
I'm definitely not a Go expert (or even novice ), but as @max.haredoom mentioned, you can allocate variables in the function signature itself. In that way, you can also omit the s
in the 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}
In the examples that I have come across in Effective Go, it does seem to be the most common way of doing things of this nature, but again, I am definitely not an authority on the subject (and will look for additional info on the actual performance).
答案3
得分: 0
我认为我通过使用defer找到了答案。
我更新了函数,以便对myStruct值进行延迟修改。这意味着它会在返回之后但在接收到另一端之前发生。
当我这样做时,调用者接收到的结构体不显示更新后的值,所以看起来我确实返回了一个副本。
func New() myStruct {
s := myStruct{}
defer func() {
s.mystring = "新值" // 延迟更新值
}()
s.mystring = "字符串"
s.myint = 1
return s
}
func main() {
b := New()
fmt.Println(b) // 仍然显示原始值
}
http://play.golang.org/p/WWQi8HpDny
英文:
I think I found the answer by using defer.
I updated the function so that there's a deferred modification to the myStruct value. This means it will happen after the return, but before it is received on the other end.
When I do this, the struct that is received by the caller does not show the updated value, so it appears as though I am indeed returning a copy.
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论