2012-12-20 18 views
12

Jeśli mam struct jak tenGo: Czy tworzę zbyt wiele wartości?

type myStruct struct { 
    mystring string 
    myint int 
} 

i jeśli mam funkcji, która zwraca nowy myStruct jak ten

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

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

    return s 
} 

Bo najpierw zapisać go w „s” zmienna przed wpuszczeniem go , czy moja funkcja faktycznie tworzy 2 wartości myStruct zamiast jednego?

A jeśli tak, czy lepszą praktyką jest upewnienie się, że najpierw nie przechowuję go w zmiennej?

+0

nie jestem pewien, ale pamiętam było jak składnia 'func Nowa() (s myStruct) {...} 'które spowodowałoby przydzielenie wyniku dla ciebie. To może być szybciej. Czy używasz google go lub gccgo? –

+0

Używam polecenia Google go. Byłbym ciekawy, czy ta składnia miałaby taki sam skutek, czy też jakoś uniknie problemu. –

+0

zobacz akceptowaną odpowiedź ... definiując ją jako 'func New() (s myStruct)' pozwoli kompilatorowi przydzielić strukturę dla ciebie przed wejściem do twojego ciała funkcji. powinno działać tak samo jak odpowiedź od jdi. nadal nie możesz być tego pewien, ponieważ specyfikacje/implementacje go zmieniają się na stałe. –

Odpowiedz

11

Oświadczenie return powróci kopię wartości obiektu myStruct. Jeśli jest to mały obiekt, to jest w porządku.

Jeśli zamierzają do rozmówcy, aby móc modyfikować ten obiekt, a struktura będzie miała metod użyć wskaźnika jako odbiornik, to ma więcej sensu zwracają wskaźnik do struktury Zamiast:

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

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

    return &s 
} 

można zobaczyć kopię dzieje, jeśli porównać adres pamięci wartości vs rodzajów powrotów wskazówka: 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

Dzięki, w tym konkretnym przypadku chcę zwrócić myStruct wartość zamiast wskaźnika, ale wydaje się, że masz rację, że zwraca kopię, chyba że deklaruję 's' w sygnaturze funkcji, która wydaje się dawać inne zachowanie. –

+0

Ach tak, patrząc na adres pamięci całkowicie to dla mnie wyczyści. Dzięki wielkie! –

+0

Ha, wiele się nauczyłeś z odpowiedzi na pytania w Pythonie, teraz ucząc się z twoich odpowiedzi na Go - znów dałbym +1, gdybym mógł. – RocketDonkey

3

Zdecydowanie nie jestem ekspertem Go (a nawet nowicjuszem :)), ale jak wspomniałem wyżej @ max.haredoom, można przydzielić zmienne w samym sygncie funkcji. W ten sposób można również pominąć s w 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} 

w przykładach, że mam natknąć w Effective Go, to wydaje się być najbardziej popularnym sposobem robienia rzeczy tego rodzaju, ale znowu , Zdecydowanie nie jestem autorytetem w tej sprawie (i będę szukać dodatkowych informacji na temat rzeczywistej wydajności).

+0

Dzięki. Myślę, że znalazłem, że moja oryginalna wersja tworzyła kopię, ale wykonując ten sam test przy użyciu twojej wersji, wydaje się, że unika się tej kopii. Oto test, którego użyłem, ale zaktualizowany twoim rozwiązaniem. http: //play.golang.org/p/66mqsVFbs_ –

+0

Po prostu nie idź zbyt szalony z ukrytymi zwrotami, w większości przypadków są to złe praktyki – jozefg

+0

@jozefg Tak, dobry punkt :) – RocketDonkey

0

Myślę, że znalazłem odpowiedź za pomocą odroczenia.

Zaktualizowałem funkcję tak, aby nastąpiła odroczona modyfikacja wartości myStruct. Oznacza to, że stanie się to po powrocie, ale przed jego otrzymaniem na drugim końcu.

Kiedy to zrobię, struktura odebrana przez wywołującego nie pokazuje zaktualizowanej wartości, więc wygląda na to, że rzeczywiście zwracam kopię.

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

Powiązane problemy