Luk*_*e B 45 error-handling exception-handling go
使用以下代码,如果没有给出文件参数,则会panic: runtime error: index out of range
按预期为第9行引发混乱.
我怎样才能"抓住"这种恐慌并在直接传递某些东西时处理它(os.Args[1]
)导致恐慌?很像PHP中的try/catch或者Python中的try/except.
我在StackOverflow上搜索了一下,但是我找不到任何可以解决这个问题的东西.
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Println("Could not open file")
}
fmt.Printf("%s", file)
}
Run Code Online (Sandbox Code Playgroud)
fuz*_*fuz 92
恐慌程序可以使用内置函数恢复recover()
:
该
recover
功能允许程序管理恐慌goroutine的行为.假设一个函数G
推迟一个函数D
调用,recover
并且在G
正在执行的同一个goroutine中的函数中发生恐慌.当延迟函数的运行到达时D
,D
调用的返回值recover
将是传递给调用的值panic
.如果D
正常返回,而不启动新的panic
,恐慌序列将停止.在这种情况下,调用之间G
调用的函数的状态和调用将panic
被丢弃,并恢复正常执行.然后运行G
之前延迟的任何函数,D
并G
通过返回其调用者来终止执行.如果满足以下任何条件,则恢复的返回值为零:
panic
的论点是nil
;- goroutine并不恐慌;
recover
没有被延期函数直接调用.
以下是如何使用此示例:
// access buf[i] and return an error if that fails.
func PanicExample(buf []int, i int) (x int, err error) {
defer func() {
// recover from panic if one occured. Set err to nil otherwise.
if (recover() != nil) {
err = errors.New("array index out of bounds")
}
}()
x = buf[i]
}
Run Code Online (Sandbox Code Playgroud)
请注意,恐慌通常不是正确的解决方案.Go范例是明确检查错误.如果在普通程序执行期间没有发生恐慌的情况,程序应该只是恐慌.例如,无法打开文件是可能发生的事情,不应该在内存耗尽时引起恐慌值得恐慌.尽管如此,这种机制的存在是为了能够捕捉到这些情况并且可能优雅地关闭.
One*_*One 40
Go不是python,你应该在使用之前正确检查args:
func main() {
if len(os.Args) != 2 {
fmt.Printf("usage: %s [filename]\n", os.Args[0])
os.Exit(1)
}
file, err := os.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", file)
}
Run Code Online (Sandbox Code Playgroud)
Vol*_*ker 14
第一:你不想这样做.Try-catch式错误处理不是错误处理.在Go中,您将len(os.Args)
首先检查并仅在存在时访问元素1.
对于极少数情况,您需要捕捉恐慌(并且您的情况不是其中之一!)defer
与之结合使用recover
.请参阅http://golang.org/doc/effective_go.html#recover
Luc*_*ato 13
一些Golang官方软件包使用panic/defer + recover作为throw/catch,但仅当他们需要解开大型调用堆栈时.在Golang的json包中使用panic/defer + recover作为throw/catch是最优雅的解决方案.
来自http://blog.golang.org/defer-panic-and-recover
有关恐慌和恢复的真实示例,请参阅Go标准库中的json包.它使用一组递归函数对JSON编码的数据进行解码.当遇到格式错误的JSON时,解析器调用panic将堆栈展开到顶级函数调用,该函数调用从恐慌中恢复并返回适当的错误值(请参阅解码中的decodeState类型的'error'和'unmarshal'方法) .走).
搜索d.error(
在http://golang.org/src/encoding/json/decode.go
在您的示例中,"惯用"解决方案是在使用它们之前检查参数,正如其他解决方案所指出的那样.
但是,如果你想要/需要抓住任何你可以做的事情:
package main
import (
"fmt"
"os"
)
func main() {
defer func() { //catch or finally
if err := recover(); err != nil { //catch
fmt.Fprintf(os.Stderr, "Exception: %v\n", err)
os.Exit(1)
}
}()
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Println("Could not open file")
}
fmt.Printf("%s", file)
}
Run Code Online (Sandbox Code Playgroud)
我必须在测试用例中捕捉恐慌。我被重定向到这里。
函数go
var errUnexpectedClose = errors.New("Unexpected Close")
func closeTransaction(a bool) {
if a == true {
panic(errUnexpectedClose)
}
}
Run Code Online (Sandbox Code Playgroud)
func_test.go
func TestExpectedPanic() {
got := panicValue(func() { closeTransaction(true) })
a, ok := got.(error)
if a != errUnexpectedClose || !ok {
t.Error("Expected ", errUnexpectedClose.Error())
}
}
func panicValue(fn func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
fn()
return
}
Run Code Online (Sandbox Code Playgroud)
从https://github.com/golang/go/commit/e4f1d9cf2e948eb0f0bb91d7c253ab61dfff3a59使用(参考来自 VonC)
我们可以使用recover 在不停止进程的情况下管理恐慌。通过使用 defer 在任何函数中调用恢复,它将执行返回到调用函数。Recover 返回两个值,一个是布尔值,另一个是要恢复的接口。使用类型断言我们可以获得底层错误值您还可以使用recover 打印底层错误。
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("pkg: %v", r)
}
}
}()
Run Code Online (Sandbox Code Playgroud)