2016-02-11 65 views
0

我在Go中很新,並且無法理解處理恐慌的最佳方式。我可以寫我自己的panic("bad data or empty source"),我會在代碼在這個地方失敗的輸出上測試,但是如何處理在不是我的方法中產生的恐慌。轉:恐慌處理或發生了什麼

現在我有這樣的錯誤:

C:/gocode/src/github.com/revel/revel/panic.go:26 (0x4975a4) handleInvocationPanic: c.Response.Out.Write(debug.Stack()) 
C:/gocode/src/github.com/revel/revel/panic.go:12 (0x4b60ca) PanicFilter.func1: handleInvocationPanic(c, err) 
c:/go/src/runtime/asm_amd64.s:437 (0x45cc75) call32: CALLFN(·call32, 32) 
c:/go/src/runtime/panic.go:423 (0x42ec17) gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) 
C:/gocode/src/github.com/revel/revel/intercept.go:93 (0x4b6061) InterceptorFilter.func1: panic(err) 
c:/go/src/runtime/asm_amd64.s:437 (0x45cc75) call32: CALLFN(·call32, 32) 
c:/go/src/runtime/panic.go:423 (0x42ec17) gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) 
c:/go/src/runtime/panic.go:42 (0x42d280) panicmem: panic(memoryError) 
c:/go/src/runtime/signal_windows.go:161 (0x44233d) sigpanic: panicmem() 
C:/gocode/src/github.com/oculus/libs/funcs.go:13 (0x4e0ca5) GetDatesInRange: fmt.Println(err.Error()) 
C:/gocode/src/github.com/oculus/rest/app/controllers/kpi.go:97 (0x4e3b2f) KpiCtrl.GetNoagg: dates, errors := libs.GetDatesInRange(request.Filters.DayStart, request.Filters.DayEnd) :97 (0x4e9f12) 
c:/go/src/runtime/asm_amd64.s:437 (0x45cc75) call32: CALLFN(·call32, 32) 
c:/go/src/reflect/value.go:432 (0x471591) Value.call: call(frametype, fn, args, uint32(frametype.size), uint32(retOffset)) 
c:/go/src/reflect/value.go:300 (0x470258) Value.Call: return v.call("Call", in) 
C:/gocode/src/github.com/revel/revel/invoker.go:36 (0x496e51) ActionInvoker: resultValue = methodValue.Call(methodArgs)[0] 
C:/gocode/src/github.com/revel/revel/compress.go:47 (0x487f89) CompressFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/intercept.go:103 (0x4954b9) InterceptorFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/oculus/rest/app/init.go:37 (0x4e2366) glob.func1: fc[0](c, fc[1:]) // Execute the next filter stage. 
C:/gocode/src/github.com/revel/revel/i18n.go:155 (0x4947a3) I18nFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/validation.go:191 (0x4ae27d) ValidationFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/flash.go:46 (0x490ee7) FlashFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/session.go:149 (0x4a914c) SessionFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/params.go:133 (0x499116) ParamsFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/filterconfig.go:208 (0x490a64) FilterConfiguringFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/router.go:474 (0x4a61e6) RouterFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/panic.go:15 (0x4972c8) PanicFilter: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/watcher.go:232 (0x4b512d) glob.func31: fc[0](c, fc[1:]) 
C:/gocode/src/github.com/revel/revel/server.go:50 (0x4a6d95) handleInternal: Filters[0](c, Filters[1:]) 
C:/gocode/src/github.com/revel/revel/server.go:38 (0x4a68f6) handle: handleInternal(w, r, nil) 
c:/go/src/net/http/server.go:1422 (0x57cfe1) HandlerFunc.ServeHTTP: f(w, r) 
c:/go/src/net/http/server.go:1862 (0x57f285) serverHandler.ServeHTTP: handler.ServeHTTP(rw, req) 
c:/go/src/net/http/server.go:1361 (0x57ca85) (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req) 
c:/go/src/runtime/asm_amd64.s:1721 (0x45f121) goexit: BYTE $0x90 // NOP 

我應該如何與他們合作,或者如何確定哪裏是麻煩。這段時間對我來說這並不重要。

回答

4

Go中您可以從恐慌中恢復,該恐慌包含恐慌錯誤消息。恢復後,你可以分析恐慌發生的原因。爲了從恐慌中恢復,您可以使用defer聲明,顧名思義,它延遲聲明的執行。這意味着你可以跳過一些事件來掛斷系統,這不是一個好的解決方案。最好的解決方案是捕捉錯誤並充分處理它們。如果錯誤發生在某些第三方框架上,這應該由他們的創建者來解決。如果沒有,你應該檢查你的代碼爲什麼會恐慌。

這裏恐慌的代碼片段恢復:

defer func() { 
    if err := recover(); err != nil { 
     fmt.Printf("Recovered from panic. %s", err) 
    } 
}() 

這裏是如何在恐慌和恢復方法使用的生成一個簡單的例子:

package main 

import "fmt" 

func badCall() { 
    panic("Bad call happend!") 
} 

func test() { 
    defer func() { 
     if err := recover(); err != nil { 
      fmt.Printf("Panicking %s\n\r" , err) 
     } 
    }() 

    badCall() 
    fmt.Println("This is never executed!!") 
} 

func main() { 
    fmt.Println("Start testing") 
    test() 
    fmt.Println("End testing") 
} 

http://play.golang.org/p/Uz9W76SfRT

如果在延期功能內調用恢復,則堆棧停止展開並恢復返回傳遞給恐慌的值(作爲interface{}!)。這意味着你可以通過一個接口作爲參數傳遞給恐慌的方法,如:

type ParseError struct { 
    Index int // The index into the space-separated list of words. 
    Word string // The word that generated the parse error. 
    Error error // The raw error that precipitated this error, if any. 
} 

// String returns a human-readable error message. 
func (e *ParseError) String() string { 
    return fmt.Sprintf("pkg: error parsing %q as int", e.Word) 
} 

// ... some code 
if err != nil { 
    panic(&ParseError{idx, field, err}) 
} 
// ... some code 

然後你就可以分析遞延聲明傳遞的接口。

閱讀這篇文章: https://github.com/golang/go/wiki/PanicAndRecover

+0

我應該在哪裏使用它,如果我寫的框架像陶醉。或者,你能給我一個簡單代碼的例子,它可以產生恐慌,並且你可以用你建議的方式處理它嗎?喜歡的例子可以在go playground上運行:https://play.golang.org/ – Altenrion

+0

@Altenrion請參閱示例代碼,瞭解如何使用恐慌和恢復。 –

+0

你的代碼片段很棒,但它說明了這種情況,當我對自定義消息感到恐慌時。如果一些圖書館會得到錯誤的參數,恐慌怎麼辦?它會以同樣的方式表現,還是不會像我的questiin中的消息一樣? – Altenrion

2

您可以使用這段代碼,並將其放置在每一個功能

defer func() { 
    if err := recover(); err != nil { 
    fmt.Println("Panic Occured and Recovered in, Error Info: ", err) 
    } 
}() 

試試這個它會爲你工作。