Resource management, popularly speaking: is the connection data needs to be closed, when operating files, open files, must remember to close; When a process is locked, the lock needs to be released. ; An error indicates that an exception has occurred in the program. Suppose we are trying to open a file that does not exist on the file system. This is an exception and represents an error.
Defer to invoke
Resource management, popularly speaking: is the connection data needs to be closed, when operating files, open files, must remember to close; When a process is locked, the lock needs to be released
-
Ensure that the call occurs at the end of the function
Func tryDefer() {defer fmt.println(1) fmt.println(2)Copy the code
Note that the call to defer occurs at the end of the function
Func tryDefer() {defer fmt.println(1) defer fmt.println(2) fmt.println(3)Copy the code
Note that defer is like a stack, so output 3, 2, 1
func tryDefer() { defer fmt.println(1) defer fmt.println(2) fmt.println(3) panic("error occurred") fmt.println(4) } // 3, 2, 1 Panic: Error occurredCopy the code
Note Defer has a higher priority than Panic, return. Panic cannot prevent the defer statement from executing even if there is a return in the code
func tryDefer2() { for i := 0; i< 100; I ++ {defer FMT.Println(I) if I == 30 {panic("printed too many")}}} 0Copy the code
Note Please defer in and out
-
Use the defer the Open/Close
The Fibonacci sequence is written to the file
Func writeFile(filename string) {// Create a file file, err := os.Create(filename) if err! = nil {panic(err)} // Close the file and defer file.close () writer := bufio.newwriter (file) defer writer.flush () // import // call Var f = fib.fibonacci () for I := 0; i < 20; I++ {FMT. Println (writer, f())}Copy the code
-
The Lock/Unlock using the defer
-
Use the defer PrintHeader/PrintFooter
Error handling concept
An error indicates that an exception has occurred in the program. Suppose we are trying to open a file that does not exist on the file system. This is an exception and represents an error.
func writeFile(filename string) { file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666) if err ! = nil {panic(err)} defer file.close () writer := bufio.newwriter (file) defer writer.flush () // import var f = fib.Fibonacci() for i := 0; i < 20; i++ { fmt.Fprintln(writer, f()) } }Copy the code
os.O_CREATE
The file will be created if it does not existos.O_EXCL
Used with O_CREATE, the file cannot exist.
Panic exceptions terminate the program, and the return exception format is too blunt, so you need to handle the exception manually
if err ! = nil {FMT. Println ("file already exists")}Copy the code
What is error
- View the source code
// Error built-in interface type is normal interface // indicates error condition, nil indicates no error. type error interface { Error() string }Copy the code
- The above exception handling can be optimized
if err ! = nil { fmt.Println("Error:", err,Error()) }Copy the code
- manually
error
err = errors.New("this is error handling") if err ! = nil { if pathError, ok := err.(*os.PathError); ! ok { panic(err) } else { fmt.Printf("%s, %s, %s\n", pathError.Op, pathError.Path, pathError.Err) } }Copy the code
The server handles exceptions in a unified manner
Implementing a unified Error Handling service (I)
-
Create the filelistingServer directory and create web.go
package main import ( "io/ioutil" "net/http" "os" ) func main() { http.HandleFunc("/list/", Func (writer http.responsewriter, request * http.request){path := request.url. path [len("/list/"):] Err := os.Open(path) // Open the file if err! = nil {// panic(err)} defer file.close () // Close the resource all, err: = ioutil.readall (file) if err! = nil {panic(err)} writer.write (all)}) // Start the listener service err := HTTP.ListenAndServe("8888", nil) if err! = nil { panic(err) } }Copy the code
-
encapsulation
Extract the above business code processing into a separate file; Create a directory –> create a file handle.go
package filelisting import ( "io/ioutil" "net/http" "os" ) func HandleFileList (writer http.ResponseWriter, Request *http. request) error {path := request.url. path [len("/list/"):] // Path file, err := os.open (path) if err! = nil { return err } defer file.Close() all, err := ioutil.ReadAll(file) if err ! = nil { return err } writer.Write(all) }Copy the code
When an exception is encountered, it is thrown directly and handled separately in the invocation layer
-
Modify the web.go file
package main import ( "net/http" "os" "github.com/StudyGo/errorhandling/filelistingserver/filelisting" "Github.com/gpmgo/gopm/modules/log") / / define structure type appHandle func (writer HTTP ResponseWriter, Request *http. request) error // Input a function, output a function, func errWrapper(handler appHandle) func(http.responsewriter, *http.Request) { return func(writer http.ResponseWriter, request *http.Request) { err := handler(writer, request) if err ! = nil { log.Warn("Error handling request: %s", err.Error()) code := http.StatusOK switch { case os.IsNotExist(err): code = http.StatusNotFound case os.IsPermission(err): code = http.StatusForbidden default: code = http.StatusInternalServerError } http.Error(writer, http.StatusText(code), code) } } } func main() { http.HandleFunc("/list/", errWrapper(filelisting.HandleFileList)) err := http.ListenAndServe(":8888", nil) if err ! = nil { panic(err) } }Copy the code
Implementing a unified error Handling service (II)
Modification based on error handling service (I); In this case, the creator of the Handle file writes the file path as a fixed value /list/, and the person calling the function gives the/path argument. The measured: http://127.0.0.1:8888/abc directly to collapse, and not to throw out the above packaging error
- Modify the
web.go
file
func errWrapper(handler appHandle) func(http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, Request * http.request) {defer func() {r := recover() log.error ("panic: %v", r) http.Error(writer, http.StatusText(http.StatusInternalServerError), HTTP. StatusInternalServerError)} () / / core End err: = handler (writer, request) if err! = nil { log.Warn("Error handling request: %s", err.Error()) code := http.StatusOK switch { case os.IsNotExist(err): code = http.StatusNotFound case os.IsPermission(err): code = http.StatusForbidden default: code = http.StatusInternalServerError } http.Error(writer, http.StatusText(code), code) } } }Copy the code
- right
handle.go
File modification again
package filelisting import ( "errors" "io/ioutil" "net/http" "os" "strings" ) const prefix = "/list/" type userError string func (e userError) Error() string { return e.Message() } func (e userError) Message() string { return string(e) } Func HandleFileList (writer http.ResponseWriter, request *http. request) error { If strings.Index(request.url.path, prefix)! = 0{return errors.New("path must start with "+ prefix)} path := request.url. path [len(prefix):] // Path file, err := os.Open(path) if err ! = nil { return err } defer file.Close() all, err := ioutil.ReadAll(file) if err ! = nil { return err } writer.Write(all) return nil }Copy the code
- right
web.go
File modification
package main import ( "net/http" "os" "github.com/StudyGo/errorhandling/filelistingserver/filelisting" "github.com/gpmgo/gopm/modules/log" ) type appHandle func(writer http.ResponseWriter, request *http.Request) error func errWrapper(handler appHandle) func(http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, request *http.Request) { defer func() { if r := recover(); r ! = nil { log.Error("panic: %v", r) http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } }() err := handler(writer, request) if err ! = nil { log.Warn("Error handling request: If userErr, ok := err.(userError); if userErr, ok := err. ok { http.Error(writer, userErr.Message(), http.StatusBadRequest) return } code := http.StatusOK switch { case os.IsNotExist(err): code = http.StatusNotFound case os.IsPermission(err): code = http.StatusForbidden default: code = http.StatusInternalServerError } http.Error(writer, http.StatusText(code), code) } } } type userError interface { error Message() string } func main() { http.HandleFunc("/", errWrapper(filelisting.HandleFileList)) err := http.ListenAndServe(":8888", nil) if err ! = nil { panic(err) } }Copy the code
The user is prompted with relatively friendly information and is not uniformly returned with Internet Error
Panic and recover
panic
- Stops the current function execution
- Go all the way up and execute each layer
defer
- If we don’t meet
recover
, program exit
recover
- Only in the
defer
Use in the call - You can get
panic
The value of the - If no, try again
panic
The sample
New recover. Go
Package main import (" FMT ") func tryRecover() {// Defer func() {r := recover() if err, ok := r.(error); ok { fmt.Println("Error occurred: ", err) } else { panic(fmt.Sprintf("I don't know what to do: %v", r)) } }() //panic(errors.New("this is an error recover")) //b := 0 //a := 5 / b //fmt.Println(a) panic(123445) } func main() { tryRecover() }Copy the code
error vs panic
- No surprise: use
error
- Unexpected: use
panic
.several groups crossed the line