2015-12-17 14 views
11

I The Go Programmiersprache Buch lese und in seiner Beschreibung des Fehlers Paket und die SchnittstelleWarum eine Struktur ist error, kein String

package errors 

type error interface { 
    Error() string 
} 

func New(text string) error { return &errorString{text} } 

type errorString struct { text string } 

func (e *errorString) Error() string { return e.text } 

es sagt

Der zugrunde liegende Typ von errorString ist eine Struktur, keine Zeichenfolge, um ihre Darstellung vor unbeabsichtigten (oder vorsätzlichen) Aktualisierungen zu schützen.

Was bedeutet das? Würde das Paket den zugrunde liegenden Typ nicht verbergen, da errorString nicht exportiert wird?

aktualisieren Hier ist der Testcode I errorString stattdessen eine string verwendet, um die Umsetzung. Beachten Sie, dass Sie eine Zeichenfolge nicht einfach als Fehler zuweisen können, wenn Sie versuchen, sie aus einem anderen Paket zu verwenden.

package testerr 

type Error interface { 
     Error() string 
} 

func New(text string) Error { 
     return errorString(text) 
} 

type errorString string 

func (e errorString) Error() string { return string(e) } 

und -prüfung es mit den vorgeschlagenen Codes

func main() { 
    err := errors.New("foo") 
    err = "bar" 
    fmt.Prinln(err) 
} 

Wird bis ein Fehler enden beim Kompilieren

cannot use "bar" (type string) as type testerr.Error in assignment: string does not implement testerr.Error (missing Error method)

Natürlich gibt es ein Nachteil dazu da unterschiedliche Fehler, die dieselbe Fehlerzeichenfolge haben, werden als gleichwertig bewertet, was wir nicht wollen.

Antwort

5

Die Erklärung des Buches über "Schutz vor versehentlichen Aktualisierungen" sieht für mich irreführend aus. Ob errorString eine Struktur oder eine Zeichenfolge ist, die Fehlermeldung ist immer noch eine Zeichenfolge und eine Zeichenfolge ist immutable by specification.

Dies ist auch keine Debatte über Einzigartigkeit. Zum Beispiel errors.New("EOF") == io.EOF wertet false aus, obwohl beide Fehler genau die gleiche zugrunde liegende Nachricht haben. Gleiches würde gelten, auch wenn errorString eine Zeichenfolge ist, solange errors.Newein Zeiger auf zurückkehren würde es (see my example.)

Sie eine Struktur könnte sagen Umsetzung error idiomatischen ist da, dass auch ist, wie die Standardbibliothek benutzerdefinierte Fehler führt . Werfen Sie einen Blick auf SyntaxError aus dem encoding/json Paket:

type SyntaxError struct { 
     Offset int64 // error occurred after reading Offset bytes 
     // contains filtered or unexported fields 
} 

func (e *SyntaxError) Error() string { return e.msg } 

(source)

Auch Implementieren einer Struktur, die error Schnittstelle keine Auswirkungen auf die Leistung hat und nicht verbrauchen mehr Speicher über einen String-Implementierung. Siehe Go Data Structures.

+0

Bitte überprüfen Sie die Bearbeitung. – shebaw

+1

@shebaw ich sehe. Ich habe die "Fehler" -Schnittstelle aus der Gleichung heraus gelassen. Ich habe meine Antwort überarbeitet. –

+0

Ich denke, dass und die zweite Erklärung, die das Buch gibt, ist, hatte wir 'errorString' zu einer Zeichenkette gemacht, dann wird jeder Fehler, der dieselbe Fehlermeldung hat, zu' True' ausgewertet. Bsp .: 'io.EOF == errors.New (" EOF ")' was falsch ist. – shebaw

3

Ihr testerr Paket funktioniert ziemlich gut, aber es verliert ein wichtiges Merkmal des „Struktur-basierten“ Standardfehler Pakets: Die von un-Gleichheit:

package main 
import ("fmt"; "testerr"; "errors") 

func main() { 
    a := testerr.New("foo") 
    b := testerr.New("foo") 
    fmt.Println(a == b) // true 

    c := errors.New("foo") 
    d := errors.New("foo") 
    fmt.Println(c == d) // false 
} 

Mit errorString ein einfachen String verschiedene Fehler mit dem Wesen der gleiche String-Inhalt wird gleich.Der ursprüngliche Code verwendet einen Zeiger auf struct, und jeder New weist eine neue Struktur zu, so dass die verschiedenen Werte, die von New zurückgegeben werden, im Vergleich zu ==, wenngleich der gleiche Fehlertext, unterschiedlich sind.

Kein Compiler darf hier den gleichen Zeiger erzeugen. Und dieses Merkmal von "verschiedenen Aufrufen von Neuem erzeugt unterschiedliche Fehlerwerte" ist wichtig, um unbeabsichtigte Fehlergleichheit zu verhindern. Ihr Tester kann geändert werden, um diese Eigenschaft zu erhalten, indem Sie *errorString implementieren Error implementieren. Probieren Sie es aus: Sie brauchen ein temporäres, um die Adresse zu nehmen. Es fühlt sich falsch an. Man könnte sich einen fancy Compiler vorstellen, der die String-Werte internalisiert und den gleichen Zeiger zurückgibt (da er auf dieselbe internalisierte Zeichenkette verweist), die diese nette Ungleichungseigenschaft aufbrechen würde.

Verwandte Themen