2013-04-20 139 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 
}