在Go语言中,处理错误的惯用方式是使代码保持DRY(Don’t Repeat Yourself)。

huangapple go评论113阅读模式
英文:

Go error handling, what's the idiomatic way for making things DRY

问题

考虑以下在Go语言中实现的原始栈示例程序:

package main

import "fmt"
import "errors"

const MAX_SIZE = 10

var a [10]int
var top int = -1

func main() {
    printStack()
    push(1)
    printStack()
    push(23)
    printStack()
    pop()
    push(2)
    push(24)
    push(56)
    push(87)
    push(97)
    push(47)
    push(37)
    push(31)
    push(69)
    printStack()
    push(75)
    println("Top element is", getTop())
}

func push(x int) (int, error) {
    if top >= (MAX_SIZE - 1) {
        return 0, errors.New("Error: Prevented Stackoverflow. Stack full")
    }
    top += 1
    a[top] = x
    return 0, nil
}

func pop() {
    top -= 1
}

func getTop() int {
    return a[top]
}

func printStack() {
    fmt.Println(top+1, "Stack:", a, "Top", top)
}

现在,我阅读了Error handling and Go,似乎上述返回多个值的方式是处理Go语言中的错误的方式。

但是,我不明白的是,Go语言的开发者是否在每个语句上都检查错误?作为来自其他语言的开发者,我对这个概念有些难以理解。所以问题是:

  1. 在上述问题中,处理错误的惯用方式是什么?
  2. 如果我不检查错误,是否被认为是一种不好的做法?如果是的话,我应该在每次调用push()时检查输出吗?

基本上,我想知道一个有经验的Go语言开发者在上述程序中如何处理错误。

Play链接:https://play.golang.org/p/_AnZLvY-28

[更新]
添加了一个从数据库获取数据并输出为JSON的真实世界程序。http://play.golang.org/p/dDApCYprjU

英文:

Consider the following example program which is primitive stack implementation in Go:

package main

import "fmt"
import "errors"

const MAX_SIZE = 10

var a [10]int
var top int = -1

func main() {
	printStack()
	push(1)
	printStack()
	push(23)
	printStack()
	pop()
	push(2)
	push(24)
	push(56)
	push(87)
	push(97)
	push(47)
	push(37)
	push(31)
	push(69)
	printStack()
	push(75)
	println("Top element is", getTop())
}

func push(x int) (int, error) {
	if top >= (MAX_SIZE - 1) {
		return 0, errors.New("Error: Prevented Stackoverflow. Stack full")
	}
	top += 1
	a[top] = x
	return 0, nil
}

func pop() {
	top -= 1
}

func getTop() int {
	return a[top]
}

func printStack() {
	fmt.Println(top+1, "Stack: ", a, "Top", top)
}

Now, I read Error handling and Go & it seems the above way of returning multiple values is the way to handle errors in go.

But what I don't understand is that does do gophers check of errors on every statement? Coming from other languages this concept it bit hard for me to grok. So the question is

  1. What is the idiomatic way of handling errors in above problem?
  2. Is considered a bad practice if I don't check for errors? if yes, then I am supposed to check the output of push() everytime I call it?

Basically what I want to know if how would a experienced gopher do error handling in the above program?

Play URL: https://play.golang.org/p/_AnZLvY-28

[Update]
Added a real-world program where I fetch data from database & output to json. http://play.golang.org/p/dDApCYprjU

答案1

得分: 4

是的,产生错误的惯用方法是返回多个值。处理错误的惯用方法是这样的:

val, err := myFunc()
if err != nil {
    // 处理 err
}

// 处理 val

总的来说,这是一个判断的问题,但通常最好处理错误。你编写的代码也有点不寻常,通常不会连续调用10次同一个函数,所以你需要做冗长的错误处理是由于原始代码造成的。例如,你可以使用循环:

for _, num := range []int{2, 24, 56, 87, 97, 47, 37, 31, 69} {
    _, err := push(num)
    if err != nil {
        panic(err)
    }
}

除了不处理 push 错误之外,你还有一些其他更严重的问题。一个小问题是 push 没有必要总是返回 0,为什么不只返回一个错误,而不是一个 int 和一个错误?更大的问题是 pop 不断减少 top,而 getTop 只是访问 a[top],所以如果 top 由于 pop 太多而变为负数,很容易导致运行时 panic。你可能希望在 popgetTop 函数中添加一些错误处理或其他保护措施。

英文:

Yes, the idiomatic way to produce errors is to return multiple values. The idiomatic way to handle errors is this:

val, err := myFunc()
if err != nil {
    // do something with err
}

// do something with val

At the end of the day it's a judgement call, but it's almost always good practice to handle errors. The code you're writing is also a bit unusual, you normally don't have 10 calls to the same function back-to-back, so the verbose error handling you'd have to do is more a result of the original code. For instance, you could use a loop:

for _, num := range []int{2, 24, 56, 87, 97, 47, 37, 31, 69} {
    _, err := push(num)
    if err != nil {
        panic(err)
    }
}

You have some other things that are more problematic than not handling the push errors though. One minor thing is there is no reason for push to always return 0, why not only have it return an error, instead of an int and an error? The bigger problem is that pop keeps decrementing top, and getTop just accesses a[top], so you can easily get a runtime panic if top becomes negative from having popped too much. You probably want some error handling or other safeguards in your pop and getTop functions.

答案2

得分: 0

这是处理Go语言中错误的标准方式。在错误发生后,有两个选项可以选择。

  1. 记录错误并完全退出程序。

  2. 记录错误并执行一些相关任务。

选项一的示例:

func funcX() {
    rtnval, err := funcY()
    if err != nil {
        fmt.Println("错误:", err)
        os.Exit(1)
    }
    // rtnval
}
英文:

This is a standard way of handling the errors in go-lang. There are two options that can follow after an error took place.

1.log the error and entirely quit the program

  1. log the error and do some relevant task

Option one example :

func funcX() {
	rtnval, err := funcY()
	if err != nil {
		fmt.Println("error: ", err)
		os.Exit(1)
	}
	//rtnval 
}

huangapple
  • 本文由 发表于 2015年11月8日 22:34:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/33595102.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定