2013-03-11 14 views
6

Mam funkcję, która zwraca albo Card, który jest typu struct, albo błąd.Co to jest idiomatyczny sposób zwracania struktury lub błędu?

Problem polega na tym, w jaki sposób mogę powrócić z funkcji, gdy wystąpi błąd? nil nie jest poprawny dla struktur i nie mam prawidłowej wartości zerowej dla mojego typu Card.

func canFail() (card Card, err error) { 
    // return nil, errors.New("Not yet implemented"); // Fails 
    return Card{Ace, Spades}, errors.New("not yet implemented"); // Works, but very ugly 
} 

Jedyne obejście znalazłem jest użycie *Card zamiast Card, A zrobić to albo nil gdy wystąpi błąd lub uczynić go wskazać rzeczywistą Card gdy błąd nie dzieje, ale to dość niezdarny.

func canFail() (card *Card, err error) { 
    return nil, errors.New("not yet implemented"); 
} 

Czy istnieje lepszy sposób?

EDYCJA: Znalazłem inny sposób, ale nie wiem, czy jest to idiomatyczny, czy nawet dobry styl.

func canFail() (card Card, err error) { 
    return card, errors.New("not yet implemented") 
} 

Od card to nazwana wartość zwracana, można go używać bez inicjalizacji. Jest wyzerowany na swój własny sposób, nie obchodzi mnie to, ponieważ funkcja wywołująca nie powinna używać tej wartości.

Odpowiedz

10
func canFail() (card Card, err error) { 
    return card, errors.New("not yet implemented") 
} 

myślę, że to, twój trzeci exampe, też jest w porządku. Zrozumiana zasada jest taka, że ​​gdy funkcja zwraca błąd, nie można polegać na innych wartościach zwracanych, aby uzyskać wartości znaczące, chyba że w dokumentacji wyraźnie podano inaczej. Zatem zwrócenie bezsensownego znaczenia struktury jest w porządku.

+2

To całkiem idiomatyczne, aby zwrócić wskaźnik, aby można było użyć zero. Pomaga uniknąć błędów i sprawia, że ​​wcześniejsze zwroty są łatwiejsze, gdy nie używasz nazwanych zwracanych wartości. –

+1

Chociaż na pewno jest w stanie zwrócić zero zamiast wskaźnika, nie używałbym wskaźników tylko z tego powodu. Fakt, że zwracany błąd nie został usunięty, jest wystarczający do tego, aby nie używać danych z "karty". Powinieneś sprawdzić błąd, a nie wartość. W przeciwnym razie nie ma sensu zwracać błędu w ogóle ... – weberc2

5

Na przykład

type Card struct { 
} 

func canFail() (card Card, err error) { 
    return Card{}, errors.New("not yet implemented") 
} 
+2

W tym przykładzie wartości zwracanych nie muszą nawet być nazwane. (Możesz nadal chcieć je nazwać z innych powodów lub możesz poczuć, że funkcja jest bardziej przejrzysta bez bałaganu nazwisk). – Sonia

+0

Przeczytaj pytanie i moją odpowiedź. Jest to funkcja krótka, którą należy zaimplementować później - pusty komunikat "struct" i "" jeszcze nie zaimplementowany ". Ponieważ nie mamy pojęcia, jaki kod zostanie użyty do zaimplementowania funkcji, jedynym bezpiecznym sposobem jest zwrócenie dobrze zdefiniowanych wartości niezależnie od tego, jaki kod zostanie użyty później. – peterSO

5
func canFail() (card Card, err error) { 
     if somethingWrong { 
       err = errors.New("Not yet implemented") 
       return 
     } 

     if foo { 
       card = baz 
       return 
     } 

     ... 

     // or 
     return Card{Ace, Spades}, nil 
} 
+0

Dziękuję, więc jest to semantycznie bliskie mojemu ostatniemu rozwiązaniu, chociaż trochę inne pod względem składni – Fabien

2

Jako możliwą alternatywę dla zwracania struktury, możesz rozważyć zezwolenie dzwoniącemu na przydzielenie go i zestaw parametrów funkcji.

func canFail(card *Card) (err error) { 
    if someCondition { 
     // set one property 
     card.Suit = Diamond 

     // set all at once 
     *card = Card{Ace, Spade} 
    } else { 
     err = errors.New("something went wrong") 
    } 

    return 
} 

Jeśli nie są wygodne, udając, że Go obsługuje C++ odniesienia stylu Należy również sprawdzić card za bycie nil.

https://play.golang.org/p/o-2TYwWCTL

Powiązane problemy