去:我创造了太多的价值观吗?

时间:2012-12-20 01:34:09

标签: 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值而不是一个吗?

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

3 个答案:

答案 0 :(得分:11)

return语句将返回myStruct对象值的副本。如果它是一个小物体,那么这很好。

如果您希望调用者能够修改此对象,并且该struct将具有使用指针作为接收器的方法,那么返回指向结构的指针更有意义:

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

答案 1 :(得分:3)

我绝对不是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}

在我Effective Go中遇到的例子中,它似乎是处理这种性质的最常见方式,但同样,我绝对不是这个主题的权威(并且会看起来有关实际表现的其他信息)。

答案 2 :(得分:0)

我想我通过使用延迟找到了答案。

我更新了函数,以便对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