2013-04-20 3 views
9

私は新しいことを学び、エラー処理が非常に冗長であることを発見しました。私はそれについての推論を読み、ほとんど同意しましたが、実際に作業を行うよりもエラーを処理するコードがたくさんあるようなところがいくつかあります。ここには、私が "Hello world!"というパイプを使った例があります。 catに入力し、出力を読み取り、出力します。基本的に、すべての行にエラーを処理するために3つ以上があり、私は実際に何も処理していません。goで複数のエラーを処理する

package main 

import "fmt" 
import "io" 
import "io/ioutil" 
import "os/exec" 


func main() { 
    cmd := exec.Command("cat", "-") 
    stdin, err := cmd.StdinPipe() 
    if err != nil { 
     return 
    } 
    stdout, err := cmd.StdoutPipe() 
    if err != nil { 
     return 
    } 
    err = cmd.Start() 
    if err != nil { 
     return 
    } 
    _, err = io.WriteString(stdin, "Hello world!") 
    if err != nil { 
     return 
    } 
    err = stdin.Close(); 
    if err != nil { 
     return 
    } 
    output, err := ioutil.ReadAll(stdout) 
    if err != nil { 
     return 
    } 
    fmt.Println(string(output)) 
    return 
} 

これを処理するための慣用的でクリーンな方法はありますか?私は何かが欠けているように感じる。

+1

http://stackoverflow.com/questions/15397419/go-handling-multiple-errors-elegantly?rq=1 –

答えて

7

明らかに、エラーを処理する必要があります。私たちはそれらを無視できません。例えば

、例が少ない人工的にしようと、

package main 

import (
    "fmt" 
    "io" 
    "io/ioutil" 
    "os" 
    "os/exec" 
) 

func piping(input string) (string, error) { 
    cmd := exec.Command("cat", "-") 
    stdin, err := cmd.StdinPipe() 
    if err != nil { 
     return "", err 
    } 
    stdout, err := cmd.StdoutPipe() 
    if err != nil { 
     return "", err 
    } 
    err = cmd.Start() 
    if err != nil { 
     return "", err 
    } 
    _, err = io.WriteString(stdin, input) 
    if err != nil { 
     return "", err 
    } 
    err = stdin.Close() 
    if err != nil { 
     return "", err 
    } 
    all, err := ioutil.ReadAll(stdout) 
    output := string(all) 
    if err != nil { 
     return output, err 
    } 
    return output, nil 
} 

func main() { 
    in := "Hello world!" 
    fmt.Println(in) 
    out, err := piping(in) 
    if err != nil { 
     fmt.Println(err) 
     os.Exit(1) 
    } 
    fmt.Println(out) 
} 

出力:ゴーで

Hello world! 
Hello world! 

Error Handling and Go

、エラー処理が重要です。言語のデザインと の規約では、 の例外が発生した(他の言語の例外である の例外を投げ、ときどきそれをキャッチするという慣習とは異なります)エラーを明示的にチェックすることをお勧めします。場合によっては、これによりGo コードが冗長になります。慣用については

+1

これが繰り返されるコードの多くの問題を解決していません。より良い解決方法については、[question user2303335 link to](http://stackoverflow.com/questions/15397419/go-handling-multiple-errors-elegantly)を参照してください。 – amon

+4

@amon:リンクされた質問に対する回答はすべて不満です。コアGoライブラリのサンプル[Go source code](https://code.google.com/p/go/source/browse/)を読んでください。設計上、Goコードはエラーをチェックします。あなた自身の質問にコードを書き直し、あなたが思いついたことを私たちに示してください。 – peterSO

0

、エラーを返すの被写体に触れることから始まるpeterSOの答えを指し、これはあなたの中のコールのコンテキストに関連した情報のいくつかの余分なビットでエラーをラップすることによって、さらに撮影することができます応用。

あり、操作超える反復実行は、以下のリンクでは、いくつかの非常に創造的な例で、より一般的な何かを保証する可能性がある場合であってもよいが、私はその質問にコメントとして、検討する不正なコードの例だったことがあります。Go — handling multiple errors elegantly?

これに関係なく、あなたが持っている例だけを見ると、これはメインで一回限りのものに過ぎません。対話型のPythonコンソールでやっているように混乱しているように見えるのであれば、

package main 

import (
    "fmt" 
    "io" 
    "io/ioutil" 
    "os/exec" 
) 

func main() { 
    cmd := exec.Command("cat", "-") 
    stdin, _ := cmd.StdinPipe() 
    stdout, _ := cmd.StdoutPipe() 

    cmd.Start() 
    io.WriteString(stdin, "Hello world!") 

    stdin.Close(); 
    output, _ := ioutil.ReadAll(stdout) 

    fmt.Println(string(output)) 
} 
+1

私の例は、簡潔さのために一回限りの主な機能でした。私の実際のコードでは、単にエラーを無視することはできません。 –

+0

簡潔さは完全に答えを変えることができます。コードが本当にmainを対象としている場合は、エラーが発生したときに 'log.Fatal'を使うのが適しています。これがRPC呼び出しの一部である場合は、エラーをラップしてその他の有用な情報を添付してください(失敗した場合は、私たちが持っているものを提供する必要がありますか?)。私のコメントの焦点は: 'エラーを返すことです。これは、アプリケーション内で呼び出しのコンテキストに関するいくつかの余分なビットでエラーをラップすることによってさらに引き継ぐことができます。 'エラーを無視したコードサンプルは、それ。 – dskinner

-3

このような状況では、通常はちょっと平らにします。

func myFunc() (err error) { 
    cmd := exec.Command("cat", "-") 

    stdin, err := cmd.StdinPipe();     if err != nil { return } 
    stdout, err := cmd.StdoutPipe();     if err != nil { return } 

     err = cmd.Start();       if err != nil { return } 
    _, err = io.WriteString(stdin, "Hello world!"); if err != nil { return } 
     err = stdin.Close();       if err != nil { return } 
    o, err := ioutil.ReadAll(stdout);    if err != nil { return } 

    fmt.Println(string(o)) 
    return 
} 

まだ醜いですが、少なくともそれほど垂直性は低く、いくつかの調整があります。

これはどんな種類の慣習にも従っているとは言えませんが、IMOを読むのがずっと簡単です。

+12

'gofmt'をコードに最初に適用すると、あなたの書式が破壊されます。 – peterSO

0

私はGoに数百の行を書きましたので、私は慣用的な方法を示すためにタイトルをつけません。 しかし、繰り返しの呼び出しとチェックのエラーのステップの場合、私はロジックを元に戻すと、コードを書く方が少し読みやすく、読みやすくなることが分かりました。終了条件をチェックする代わりに(err!= nil )、私は以下のように継続する条件(エラー== nil)をチェックします。
これは、エラーを処理する独自の方法がある場合でも、発信者に戻ったり印刷したりログしたりするなどのエラーはありません。 このアプローチの欠点は、変数が割り当てられているifブロックのスコープを持つため、変数を:=で暗黙的に宣言できないことです。

func main() { 
    var output []byte 
    var stdin io.WriteCloser 
    var stdout io.Reader 

    cmd := exec.Command("cat", "-") 

    stdin, err := cmd.StdinPipe() 

    if err == nil { 
     stdout, err = cmd.StdoutPipe() 
    } 

    if err == nil { 
     err = cmd.Start() 
    } 

    if err == nil { 
     _, err = io.WriteString(stdin, "Hello world!") 
    } 

    if err == nil { 
    output, err = ioutil.ReadAll(stdout) 
    } 

    if err == nil { 
    err = stdin.Close(); 
    } 

    if err == nil { 
      fmt.Println(string(output)) 
    } else { 
     fmt.Println(string(err.Error())) // Error handling goes here 
    } 

    return 
} 
関連する問題