2012-12-20 22 views
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值而不是一個?

如果是這樣,那麼確保我不首先將其存儲在變量中是一種更好的做法嗎?

+0

我不知道,但我記得有一個語法像'FUNC新()(S myStruct){...}'這會爲你分配結果。這可能會更快。你使用谷歌去或gccgo? –

+0

我正在使用Google go命令。我會好奇的,如果這種語法會有相同的效果,或者如果它以某種方式避免這個問題。 –

+0

看到接受的答案...將其定義爲'func New()(s myStruct)'將讓編譯器在進入函數體之前爲您分配結構體。它應該和jdi的答案一樣。仍然無法確定,導致go的規格/實現正在永久改變。 –

回答

11

return聲明將返回myStruct對象值的副本。如果它是一個小對象,那麼這很好。

如果您打算來電話者能夠修改該對象,該結構將具有使用指針作爲接收方法,那麼它更有意義的指針返回到您的結構,而不是:

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

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

    return &s 
} 

你可以看到副本發生在比較值的內存地址指針VS返回類型: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 
+0

謝謝,在這種特殊情況下,我想返回一個myStruct值而不是指針,但看起來你是對的,它會返回一個副本,除非我在函數簽名中聲明's',這似乎給出了不同的行爲。 –

+0

啊,是的,看着內存地址完全清除了我。非常感謝! –

+0

哈,從你的Python答案中學到了很多,現在從你的答案中學習 - 如果可以的話,我會再次+1。 – RocketDonkey

3

我絕對不是Go專家(甚至是新手:)),但正如@ max.haredoom提到的那樣,您可以在函數簽名本身中分配變量。這樣一來,你也可以省略sreturn

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的例子,它似乎是這樣性質的東西的最常用的方式,但同樣,我絕對不是這方面的權威人士(並且會尋找關於實際表現的更多信息)。

+0

謝謝。我想我發現我的原始版本正在製作副本,但是使用您的版本進行相同的測試,似乎避免了副本。以下是我使用的測試,但更新了您的解決方案。 HTTP://play.golang。org/p/66mqsVFbs_ –

+0

只是不要過於瘋狂的隱性回報,在大多數情況下,他們往往是不好的做法 – jozefg

+0

@jozefg是的,好點:) – RocketDonkey

0

我想我通過使用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