Własny ustandaryzowany typ błędu.

0

Rozumiem, że w Go zmienna jest nil jeśli jej wartość jest nil oraz jej typ jest interface{} (czy też nilowy), ale jak w takim wypadku w aplikacji ustandaryzować typ błędu zwracanego np. z Facady do Handlera (jako handler np. echo) Jeżeli stworzę własną structurę np CustomError i będę ją zwracał jako zwracany typ, to oczywiście - wartość będzie nilem, ale typ już będzie CustomError więc sama zmienna nie będzie nilem.

type CustomError struct {
	reason string // Na podstawie tego pola byłby Response Status ustalany
	message interface{}
}

func returnSomeError() (string,*CustomError) {
	return "Success",nil
}

func main() {
	_,err := returnSomeError()
	fmt.Println(err != nil) // True
}

Inny przykład - stworzyłem sobie structurę do komunikacji z serwerem autoryzacyjnym. Każda z metod zwraca dwie wartości: (*result, *ErrorResponse) (result jest różny w zależności od metody wywołwanej z tego klienta: JWT, stworzony użytkownik, informacje o tokenie itd). I w takiej jeżeli z clienta zwracam jako ErrorResponse nil to późniejsze porównanie ErrorResponse!=nil zwraca true. Wiem, że można to zrzutować na (*ErrorResponse)(err) i to już zwróci true ale to jest robienie wszystkiego na okrętkę.

I jeszcze pytanie na boku, czy zwracanie dwóch parametrów w przypadku ErrorResponse jest poprawne? Czy error powinien być przeznaczony tylko dla sytuacji stricte "programistycznych" (w sensie jak przekaże gdzieś np. 0 przy dzieleniu).

2

Coś ty tutaj za bardzo kombinujesz. Program wypisze false a nie true, bo typ zmiennej err jest wskaźnikiem a nie strukturą. To prawda że z samą strukturą nie dało by się użyć nila, ale tutaj masz wskaźnik. Jakby jeszcze zadeklarować ten type CustomError *CustomErrorStruct to nie trzeba by było pisać *.

Inne podejście z biblioteki standardowej to deklaracja interface'u dla błędu i potem implementacja tego interface'u przez strukturę. Interface może być nilem. Także to wydaje się być właściwym podejściem - tutaj jest opisane co i jak: https://www.digitalocean.com/community/tutorials/creating-custom-errors-in-go

EDIT: Lepiej po prostu wykorzystać interfejs błędu z biblioteki standardowej i dodać własną implementację.

0
Aisekai napisał(a):

Rozumiem, że w Go zmienna jest nil jeśli jej wartość jest nil oraz jej typ jest interface{} (czy też nilowy),

Trochę przekombinowałeś. nil oznacza, że wskaźnik do niczego się nie odnosi. Zarówno wskaźnik jak i interfejs mogą mieć wartość nil (dokładniej to w go zmienna typu interfejs trzyma wartość i typ tej wartości).

ale jak w takim wypadku w aplikacji ustandaryzować typ błędu zwracanego np. z Facady do Handlera (jako handler np. echo) Jeżeli stworzę własną structurę np CustomError i będę ją zwracał jako zwracany typ, to oczywiście - wartość będzie nilem, ale typ już będzie CustomError więc sama zmienna nie będzie nilem.

Nie bardzo rozumiem, co tutaj ma typ do rzeczy. Zmienna wskaźnikowa będzie nilem jeżeli została ustawiona na nil. To czy zwracasz jako drugi parametr error, nie ma tu nic do rzeczy.

type CustomError struct {
	reason string // Na podstawie tego pola byłby Response Status ustalany
	message interface{}
}

func returnSomeError() (string,*CustomError) {
	return "Success",nil
}

func main() {
	_,err := returnSomeError()
	fmt.Println(err != nil) // True
}

Przecież returnSomeError nie zwraca błędu. Uruchom ten kod chociaż :)

Inny przykład - stworzyłem sobie structurę do komunikacji z serwerem autoryzacyjnym. Każda z metod zwraca dwie wartości: (*result, *ErrorResponse) (result jest różny w zależności od metody wywołwanej z tego klienta: JWT, stworzony użytkownik, informacje o tokenie itd). I w takiej jeżeli z clienta zwracam jako ErrorResponse nil to późniejsze porównanie ErrorResponse!=nil zwraca true. Wiem, że można to zrzutować na (*ErrorResponse)(err) i to już zwróci true ale to jest robienie wszystkiego na okrętkę.

Pokaż kod, bo na 99.9% coś masz źle.

I jeszcze pytanie na boku, czy zwracanie dwóch parametrów w przypadku ErrorResponse jest poprawne? Czy error powinien być przeznaczony tylko dla sytuacji stricte "programistycznych" (w sensie jak przekaże gdzieś np. 0 przy dzieleniu).

Zwracany błąd to jakaś wartość. To nie wyjątki, które będą rozwijać stos i ktoś się przyczepi, że nie służą do regularnego sterowania pracy programem, a nie tylko w sytuacjach wyjątkowych. Możesz interpretować zwracany błąd jak sobie chcesz.

0

Mój błąd, rzeczywiście nie zwraca to błędu - wcześniej testowałem inną sytuację, chciałem ją uprościć i rzeczywiście uprościłem ją za bardzo. Coś źle zrozumiałem. Problem wynikał z tego, że zwracałem bezpośrednio rezultat z funkcji który zwracał nilowy wskaźnik na error. Ale czemu w takim wypadku, error!=nil?

type ErrorResponse struct {
	statusCode int
	message    string
}

func (err *ErrorResponse) Error() string {
	//fmt.Println(err.message) <-- Powoduje błąd
	return fmt.Sprintf("Error code: 400. Error message: message")
}

func reReturnError() error {
	return returnError()
}

func returnError() *ErrorResponse {
	return nil
}

func main() {
	err := reReturnError()

	fmt.Println(err != nil) // true
	switch err.(type) {
	case *ErrorResponse:
		fmt.Println("Err is typeof *ErrorResponse") // Err is typeof *ErrorResponse
	}
	fmt.Println(err.Error()) // Error code: 400. Error message: message
}


Wcześniej przeczytałem właśnie, że wskaźnik jest nilem oraz kiedy jej typ jest nilem (np zwracanie interfejsu). Czemu w takim razie w pierwszym poście, wszystko działa - mimo, że wskaźnik jest nilowy ale typ jest określony na *CustomError natomiast w drugim przypadku, już zwrócony wskaźnik nie jest nilem? Natomiast, jeżeli reRturnError() zwracałoby *ErrorResponse to err!=nil zwróci false.

Link do playgroundy: https://play.golang.org/p/OrOV3XLXepe

1

Ok, teraz rozumiem o co ci chodziło z typem. Zmieszałeś różne koncepcje.
Tak działaj zmienne typu interfejs w go. Przeczytaj https://golang.org/doc/faq#nil_error

1 użytkowników online, w tym zalogowanych: 0, gości: 1