Google资深工程师深度讲解Go语言-错误处理和资源管理(七)「建议收藏」

Google资深工程师深度讲解Go语言-错误处理和资源管理(七)

大家好,又见面了,我是全栈君。

一.defer调用:实现资源管理

  • 确保调用在函数结束时发生
  • 参数在defer语句时计算
  • defer列表为后进先出

何时使用defer调用

  • Open/Close
  • Lock/Unlock
  • PrintHeader/PrintFooter
package main

import "fmt"

func tryDefer(){
	defer fmt.Println(1)
	defer fmt.Println(2)//defer 相当于栈:先进后出
	fmt.Println(3)
	//结果:3 2 1
}
func main() {
	tryDefer()
}
package main

import (
	"../../functional/fib"
	"bufio"
	"fmt"
	"os"
)

func tryDefer() {
	defer fmt.Println(1)
	defer fmt.Println(2) //defer 相当于栈:先进后出
	fmt.Println(3)
	//结果:3 2 1
	//return
	panic("error occurred")
	fmt.Println(4)
	//3
	//2
	//1
	//panic: error occurred
}
//参数在defer语句时计算
func tryDefer2() {
	for i := 0; i < 100; i++ {
		defer fmt.Println(i) //
		if i == 10 {
			panic("print too many")
		}
	}
}

func writeFile(filename string) {
	file, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	defer writer.Flush()

	f := fib.Fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Fprintln(writer, f())
	}
}

func main() {
	//tryDefer()
	tryDefer2()
	writeFile("fib.txt")
}

二.错误处理理念

func writeFile(filename string) {
	//file, err := os.Create(filename)
	file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666) //O_EXCL 如果文件存在的话打开不了
	// panic: open fib.txt: file exists
	err = errors.New("this is a custum error")
	if err != nil {
		//fmt.Println("Error:",err.Error())
		if pathError, ok := err.(*os.PathError); !ok {
			panic(err)
		} else {
			fmt.Printf("%s ,%s ,%s\n ", pathError.Op, pathError.Path, pathError.Err)
		}
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	defer writer.Flush()

	f := fib.Fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Fprintln(writer, f())
	}
}

三.服务器统一出错处理

web.go

package main

import (
	"./filelisting"
	"log"
	"net/http"
	"os"
)

type appHandler func(writer http.ResponseWriter, request *http.Request) error

//错误包装
func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {
	return func(writer http.ResponseWriter, request *http.Request) {
		err := handler(writer, request)
		if err != nil {
			log.Printf("Error handing request:%s",err.Error()) //2020/08/29 17:17:36 Error handing request:open fib2.txt: permission denied
			code := http.StatusOK
			switch {
			case os.IsNotExist(err):
				//http.Error(writer, http.StatusText(http.StatusNotFound), http.StatusNotFound)
				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(":8081", nil)
	if err != nil {
		panic(err)
	}
}

handler.go

package filelisting

import (
	"io/ioutil"
	"net/http"
	"os"
)

func HandleFileList(writer http.ResponseWriter, request *http.Request) error {
	path := request.URL.Path[len("/list/"):]
	file, err := os.Open(path)
	if err != nil {
		//panic(err)
		/*http.Error(writer,
			err.Error(),
			http.StatusInternalServerError)
		return*/
		return err
	}
	defer file.Close()

	all, err := ioutil.ReadAll(file)
	if err != nil {
		//panic(err)
		return err
	}
	writer.Write(all)
	return nil
}

四.panic和recover

panin功能作用

  • 停止当前函数执行
  • 一直向上返回,执行每一层的defer
  • 如果没有遇见recover,程序退出

recover功能作用

  • 仅在defer调用中使用
  • 获取panic的值
  • 如果无法处理,可重新panic
package main

import (
	"fmt"
)

func tryRecover() {
	defer func() {
		r := recover()
		if err, ok := r.(error); ok {
			fmt.Println("Error occurred:", err)
		} else {
			fmt.Println(r)
		}
	}()

	//panic(errors.New("this is an error")) //Error occurred: this is an error,下面不执行,panic停止当前函数执行

	b := 0
	a := 5 / b
	fmt.Println(a) //Error occurred: runtime error: integer divide by zero
}
func main() {
	tryRecover()
}

五.服务器统一出错处理

  • 意料之中的:使用error,如文件打不开
  • 意料之外的:使用panic,如数组越界
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/111710.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Mybatis笔记(1)

    Mybatis笔记(1)

    2021年11月11日
    81
  • 桌面软件图标变成白纸的解决方法是什么_笔记本桌面图标变成白纸

    桌面软件图标变成白纸的解决方法是什么_笔记本桌面图标变成白纸在桌面上新建一个txt文件:在文件里输入以下内容并保存:rem关闭Windows外壳程序explorertaskkill/f/imexplorer.exerem清理系统图标缓存数据库attrib-h-s-r“%userprofile%\AppData\Local\IconCache.db”del/f“%userprofile%\AppData\Loca…

    2022年10月18日
    4
  • ArrayList扩容1.5倍

    ArrayList扩容1.5倍先写一个小案例代码packagecom.itheima.demo;importjava.lang.reflect.Field;importjava.util.ArrayList;publicclassArrayListDemo{publicstaticvoidmain(String[]args){ArrayList&lt;I…

    2022年4月28日
    32
  • c语言注释快捷键_c语言多行注释快捷键

    c语言注释快捷键_c语言多行注释快捷键//注释多行快捷键Ctrl+kctrl+l//解注释多行快捷键Ctrl+kctrl+u

    2022年8月15日
    7
  • Qi v1.2.4协议 之 定频调压方案

    Qi v1.2.4协议 之 定频调压方案Qiv1.2.3 Qiv1.2.4 Tx类型 MP-A11 MP-A11 认证登记 BPP+FODExtensions EPP 注:BPP-BasicPowerProfile,EPP-ExtendedPowerProfile 市场上支持苹果发射端7.5W快充的无线充电发射器方案(一)变频架构工作原理:通过改变工作频率从而调节发射功率;在某些发射频段会对手机电路造成一定干扰;目前市场上变频架构的发射器一…

    2022年6月22日
    27
  • android之存储篇_ContentProvider存储

    ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制。一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。并且此种方式忽略了底层的数据存储实现,ContentProvider提供了一种统一的通过Uri实现数据操作的方式。其步骤为:  1. 在当前应用程序中定义一个ContentProvider。  2. 在当前应用程序的AndroidMani

    2022年3月10日
    52

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号