2013-04-20 141 views
9

我是新來的,發現錯誤處理是非常詳細的。我已經閱讀了它的推理,並且大部分都認同,但是有幾個地方似乎有更多的代碼來處理錯誤,而不是實際執行的工作。這是一個(人爲的)例子,我在這裏輸入「Hello world!」讀入並讀取並打印輸出。基本上每條線都有三個來處理錯誤,而我甚至沒有處理任何事情。在處理多個錯誤

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 – 2013-04-20 23:45:18

回答

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

在圍棋,錯誤處理是很重要的。該語言的設計和 慣例鼓勵您明確地檢查發生錯誤的位置(與其他語言中拋出異常並有時捕捉它們的慣例不同)。在某些情況下,這會使代碼變得冗長。

+1

這並沒有解決大量的重複代碼的問題。請參閱[問題user2303335鏈接到](http://stackoverflow.com/questions/15397419/go-handling-multiple-errors-elegantly)以獲得更好的解決方案。 – amon 2013-04-21 00:01:04

+4

@amon:鏈接問題的答案都不令人滿意。閱讀核心Go庫的示例[Go source code](https://code.google.com/p/go/source/browse/)。通過設計,Go代碼檢查錯誤。重新編寫問題中的代碼,向我們展示您的想法。 – peterSO 2013-04-21 00:09:27

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

爲了簡潔起見,我的例子是一次性的主要功能。在我的實際代碼中,我不能忽略這些錯誤。 – 2013-04-21 01:27:31

+0

簡潔可以完全改變答案。如果代碼實際上是指向main的,那麼當遇到錯誤時,使用'log.Fatal'會很合適。如果這是RPC調用的一部分,那麼封裝錯誤並附加其他有用的信息(如果我們失敗了,我們是否應該提供我們所擁有的信息?)將是合適的。我的評論的焦點是:「返回錯誤,這可以通過在應用程序中用一些額外的與調用上下文相關的信息包裝錯誤來進一步考慮。」忽略errs的代碼示例是事後才能提醒的,並且可以提醒您那。 – dskinner 2013-04-22 02:07:22

-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 2013-04-21 01:43:02

0

我剛剛在Go中寫了幾百行,所以我的名字沒有標明任何習慣用法。 但是,如果重複調用和檢查錯誤步驟,我發現代碼更容易編寫和讀取,如果我還原邏輯:而不是檢查退出條件(err!= nil ),我檢查條件是否繼續(err == 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 
}