Go:我创建的值太多了吗?

huangapple go评论78阅读模式
英文:

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专家(甚至不是新手 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 Go:我创建的值太多了吗? ), 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
}

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

huangapple
  • 本文由 发表于 2012年12月20日 09:34:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/13963991.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定