2015-12-17 18 views
11

をerrorStringにされたのはなぜ私が行くのプログラミング言語の本を読んで、それにはそれが構造体ではなく、文字列

の基になる型を言うエラーパッケージ及びインタフェース

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 } 

の説明だのですerrorStringは、意図していない(または計画された)更新からその表現を保護するための構造体であり、文字列ではありません。

これはどういう意味ですか? errorStringがエクスポートされていないので、パッケージは基になるタイプを隠さないでしょうか?

更新 ここでは、私が代わりにstringを用いerrorStringを実現使用テストコードです。別のパッケージから使用しようとすると、文字列をエラーとして割り当てることはできません。もちろん

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

をコンパイルするとき

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) } 

そして欠点が異なるため、これまで存在し

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

は誤差が生じることになります示唆したコードでそれをテストします同じエラー文字列を持つエラーは、私たちが望ましくないと評価されます。

答えて

5

「偶然の更新からの表現を保護する」という本の説明は私にとって誤解を招くようです。 errorStringが構造体でも文字列でも、エラーメッセージはまだ文字列で、文字列はimmutable by specificationです。

これは、一意性についての議論でもありません。たとえば、errors.New("EOF") == io.EOFfalseと評価されますが、両方のエラーはまったく同じ基本メッセージを持ちます。 errorStringが文字列だった場合でも、errors.Newはそれにのポインタを返すのと同じである限り、適用されます(see my example。)

あなたは構造体は、それが標準ライブラリは、カスタムエラーを紹介する方法もありますので、errorが慣用で実装すると言うことができます。 encoding/jsonパッケージからSyntaxErrorを見てみましょう:

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

はまた、errorインタフェースを実装する構造体には、パフォーマンスに影響を与えませんし、文字列の実装を超える多くのメモリを消費しません。 Go Data Structuresを参照してください。

+0

編集を確認してください。 – shebaw

+1

@shebaw私は参照してください。私は方程式の外に 'エラー'インタフェースを残しました。私は私の答えを改訂した。 –

+0

私は、この本が与える2番目の説明は、 'errorString'を文字列にしておけば、同じエラー文字列を持つエラーは' True'と評価されます。例: 'io.EOF == errors.New(" EOF ")'は間違っています。 – shebaw

3

あなたtesterrパッケージはかなりうまく動作しますが、それは「構造体ベースの」標準エラーパッケージの主要な機能失い:errorStringとプレーンな文字列であること異なるエラーで

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 
} 

:非平等のことを同じ文字列の内容が等しくなります。元のコードは構造体へのポインタを使用し、Newは新しい構造体を割り当てますので、等しいエラー・テキストではあるが==と比較すると、Newから返される異なる値が異なります。

ここで同じポインタを生成するコンパイラはありません。そして、意図していないエラーの等価性を防ぐためには、「異なる呼び出しに異なる呼び出し値を生成する」というこの機能が重要です。テスターは、*errorStringErrorを実装することによってこのプロパティを生成するように変更できます。それを試してください:アドレスを取るには一時的なものが必要です。それは間違っていると感じます。文字列の値を内部化し、同じ内部化された文字列を指すポインタと同じポインタを返す可能性のある、この素敵な不等式のプロパティを破る可能性のある派手なコンパイラを想像することができます。

関連する問題