2015-05-11 17 views
7

Właśnie zacząłem używać Golanga. Myślę, że deklaracja zmiennej błędu jest idiomatyczna i użycie jej w strukturze błędów do określenia, co poszło nie tak, jak to się dzieje w strconv.go. Tam deklarowane są ErrRange i ErrSyntax, a w razie potrzeby odniesienia do tych są przechowywane w strukturach NumError po ich powrocie. Myślę, że powodem jest to, że wtedy adres odniesienia do błędu przechowywanego w NumError można porównać ze zmiennymi ErrRange i ErrSyntax w celu ustalenia, który typ błędu został zwrócony.Czy masz standardowe zmienne Err?

Czy istnieją "standardowe" takie zadeklarowane typy błędów? W Javie na przykład masz rzeczy takie jak java.lang.IllegalArgumentException. Czy istnieje na przykład ErrArgument lub ErrUnsupportedOperation, których mogę używać w moim własnym kodzie zamiast tworzyć nowe zmienne błędów, które oznaczają to samo za każdym razem?

Odpowiedz

3

Nie, nie ma. Po prostu dostarczaj zrozumiałe błędy zamiast ogólnych. Jakie informacje ma transport IllegalArgument? Nie za dużo, za mało.

+0

Zazwyczaj, nawet kiedy piszę Pythona, który ma na języku Java, takich jak kategorie wyjątków, mój * intent * służy do obsługi określonego błędu, o którym wiem, że potrzebuję specjalnej ścieżki (np. błędu sieci wywołującego niektóre zewnętrzne API) lub złapania czegokolwiek (i np. ., log i przerwanie). Wartości potencjalnie specjalnego błędu płatka śniegu najczęściej działają. Pakiet 'os' zawiera funkcje, które kategoryzują własne błędy (np.' Os.IsPermission (err error) bool'), ale to coś zupełnie innego. – twotwotwo

2

Jak widzieliście, istnieją specyficzne błędy, których używają określone pakiety. Na przykład w pakiecie database/sql, określają:

var ErrNoRows = errors.New("sql: no rows in result set") 

Więc jeśli nie QueryRow (który odracza błędu aż Scan), a następnie Scan można zrobić

if err := row.Scan(&data); err != nil && err != sql.ErrNoRows { 
    //something actually went wrong 
} else if err != nil { 
    //no results 
} else { 
    //we found it 
} 

os/exec ma var ErrNotFound = errors.New("executable file not found in $PATH")

encoding/json ma type UnmarshalTypeError, który jest typem implementującym interfejs error.

Tak więc nie, chociaż nie ma "zestawu standardowych błędów", możesz (i najprawdopodobniej powinieneś) mieć określone zmienne błędu, których używasz ponownie.

Można mieć swój własny pakiet errorMsgs że użyjesz, w których możesz użyć typowych błędów:

err := doSomething(); if err != nil { 
    switch err { 
     case errorMsgs.IllegalArgument: 
      //do something 
     case errorMsgs.CouldNotConnect: 
      //do something else 
    } 
} 
17

Istnieje kilka typowych sposobów idiomatyczne dla autora pakietu zarabiania zwraca błąd.

  1. zmienne Naprawiono błąd, zwykle nazywane Err…

    var (
         ErrSomethingBad = errors.New("some string") 
         ErrKindFoo  = errors.New("foo happened") 
    ) 
    
  2. typy błędów, zwykle o nazwie …Error

    type SomeError struct { 
        // extra information, whatever might be useful to callers 
        // (or for making a nice message in `Error()`) 
        ExtraInfo int 
    } 
    type OtherError string 
    
    func (e SomeError) Error() string { /* … */ } 
    func (e OtherError) Error() string { 
         return fmt.Sprintf("failure doing something with %q", string(e)) 
    } 
    
  3. errors.New wartości ad hoc w zależności od potrzeb.

    func SomepackageFunction() error { 
         return errors.New("not implemented") 
    } 
    
  4. Używanie błędów zdefiniowanych w pakietach standardowych. Zwykle ograniczony do małego zestawu, takiego jak io.EOF; w większości przypadków lepiej jest tworzyć własne za pomocą metody 1 powyżej.

    func SomeFunc() error { 
         return io.EOF 
    } 
    

    Należy zauważyć, że czasem przy wprowadzaniu interfejs (na przykład metodą Read stać się io.Reader) jest jest najlepiej stosować odpowiadające błędów (lub „niezbędnych” w specyfikacji interfejsu).

  5. Dokonywanie interfejs taki jak net.Error:

    type Error interface { 
        error 
        Timeout() bool // Is the error a timeout? 
        Temporary() bool // Is the error temporary? 
    } 
    

Często będziesz używać mieszankę wszystkich tych sposobów.

Pierwszy, drugi i piąty są korzystne, jeśli uważasz dowolny użytkownikiem pakietu będzie kiedykolwiek chcesz przetestować dla konkretnych błędów. Pozwalają one takie rzeczy jak:

err := somepkg.Function() 
if err == somepkg.ErrSomethingBad { 
     // … 
} 
// or for an error type, something like: 
if e, ok := err.(somepkg.SomeError); ok && e.ExtraInfo > 42 { 
     // use the fields/methods of `e` if needed 
} 

Piąta sposób (co jest po prostu przedłużeniem drugi) umożliwia sprawdzanie błędu za zachowanie/typ tak:

if e, ok := err.(net.Error); ok && e.Timeout() { 
     // it's a timeout, sleep and retry 
} 

Problem z trzeciej drogi czy nie pozostawia rozsądnego sposobu, aby użytkownik pakietu mógł go przetestować. (Testowanie zawartości ciągu zwracanego przez err.Error() nie jest świetnym pomysłem). Jest jednak w porządku w przypadku błędów, których nikt nigdy nie chce testować.

Dalsze czytanie:

Powiązane problemy