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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 风控模型评估方法以及大数据风控模型概念

    风控模型评估方法以及大数据风控模型概念更新一下有效性指标中的区分能力指标:KS(Kolmogorov-Smirnov):KS用于模型风险区分能力进行评估,指标衡量的是好坏样本累计分部之间的差值。好坏样本累计差异越大,KS指标越大,那么模型的风险区分能力越强。KS的计算步骤如下:1.计算每个评分区间的好坏账户数。2.计算每个评分区间的累计好账户数占总好账户数比率(good%)和累计坏账户数占总坏账户数比率(bad%

    2022年6月3日
    42
  • 大数据ETL开发之图解Kettle工具(入门到精通)

    大数据ETL开发之图解Kettle工具(入门到精通)0ETL简介ETL(Extract-Transform-Load的缩写,即数据抽取、转换、装载的过程),对于企业或行业应用来说,我们经常会遇到各种数据的处理,转换,迁移,所以了解并掌握一种ETL工具的使用,必不可少。市面上常用的ETL工具有很多,比如Sqoop,DataX,Kettle,Talend等,作为一个大数据工程师,我们最好要掌握其中的两到三种,这里我们要学习的ETL工具是Kettle!1Kettle简介1.1Kettle是什么Kettle是一款国外开源的ETL工具,纯ja

    2022年6月13日
    60
  • 奇怪的电梯

    奇怪的电梯奇怪的电梯【问题描述】某栋大楼有一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1≤i<N)上有一个数字K(≤K≤N)电梯只有四个按钮:开、关、上、下。上、下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:33125代表了Ki(K1=3,K2=3,…),从一层开始。在一层按“上”可以到4层,按“下”是不起作用的,因为没有-2层。那么从A层到B层至少要按几次按钮呢?【输入格式】第1行为3个用1个空格隔开的正整数,表示N、A、B(l≤N≤200,1≤

    2022年6月14日
    40
  • ⛽zipkin2.reporter.InMemoryReporterMetrics导致服务器CPU100%及应用OOM问题排查和解决「建议收藏」

    ⛽InMemoryReporterMetrics导致线上CPU100%及服务OOM排查和解决下面是我遇到的问题,以及一些简单的排查思路,如有不对的地方,欢迎留言讨论。如果你已经遇到 InMemoryReporterMetrics 导致的OOM问题,并已经解决,则可忽略此文。若你对CPU100%以及线上问题OOM排查不清楚,可以浏览下本文。问题现象【告警通知-应用异常告警】简单看下告警的信息:拒绝连接,不要太在意马赛克。问题排查通过告警信息,知道是哪一台服务器的哪个服务出现问题。首先登录服

    2022年3月1日
    42
  • Fiddler HPPTS 配置教程「建议收藏」

    Fiddler HPPTS 配置教程「建议收藏」 思路:先清除,之前的网站证书再安装fiddler的证书。具体看下面:https://www.cnblogs.com/xiao-qing/p/7771289.html转载于:https://www.cnblogs.com/limi2019/articles/11233846.html…

    2022年10月2日
    4
  • 二叉树的最大深度和最小深度浅析

    二叉树的最大深度和最小深度浅析

    2021年9月15日
    52

发表回复

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

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