12

如果我有这样的结构

type myStruct struct {
    mystring string
    myint int
}

如果我有一个像这样返回一个新的 myStruct 的函数

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

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

    return s
}

因为我在返回之前首先将它存储在“s”变量中,所以我的函数实际上是在生成 2 个 myStruct 值而不是一个吗?

如果是这样,那么确保我不首先将其存储在变量中是一种更好的做法吗?

4

3 回答 3

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 // obj inside NewObj()
0xf840023580 // obj returned to caller
0xf840023640 // ptr inside of NewPtr()
0xf840023640 // ptr returned to caller
于 2012-12-20T02:02:06.833 回答
3

我绝对不是围棋专家(甚至不是新手 :)),但正如@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}

在我在Effective Go中遇到的示例中,它似乎确实是处理这种性质的最常见的方式,但同样,我绝对不是该主题的权威(并将寻找有关实际表现)。

于 2012-12-20T01:51:54.320 回答
0

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

于 2012-12-20T02:00:07.197 回答