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


相关推荐

  • 5G LTE窄带物联网(NB-IoT) 10

    5G LTE窄带物联网(NB-IoT) 10第7章物理子层物理子层是底层子层,负责MACPDU的物理信道,传输和接收;如图7.1所示。RRC提供PHY子层的配置参数。在MAC/PHY接口,传输信道在发送和接收时分别映射到物理信道,反之亦然[28]。 RRC将其配置参数发送到每个子层,包括PHY子层,如第4.2,5.2,6.2和7.1节所示。7.1RRC配置参数RRC将专用或默认无线电配置参数发送到PHY子层,…

    2022年10月6日
    2
  • pycharm激活码2021年最新破解方法

    pycharm激活码2021年最新破解方法,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    53
  • 分布式事务TCC方案Hmily——springcloud + feign + mybatis

    分布式事务TCC方案Hmily——springcloud + feign + mybatisTCC理论:分布式事务基础理论——TCCHmily介绍:分布式事务TCC方案——Hmily金融级柔性分布式事务解决方案介绍本文demo代码:GitHub依赖<dependency><groupId>org.dromara</groupId><artifactId>hmily-springcloud</artifactId><vers

    2022年5月13日
    69
  • 软件测试笔试面试题目完全汇总

    软件测试笔试面试题目完全汇总1、软件测试的流程2、web测试和APP测试的区别仅仅从功能测试的层面上来讲的话,在流程和功能测试上是没有区别的。那么区别在哪里呢?由于载体不一样,所以系统测试和一些细节可能会不一样。那么我们就要先来了解,web和app的区别。web项目,一般都是b/s架构,基于浏览器的,而app则是c/s的,必须要有客户端。那么在系统测试测试的时候就会产生区别了。首先从系统架构来看的话,web测试…

    2022年5月8日
    41
  • python实现——ASCII谢尔宾斯基地毯

    python实现——ASCII谢尔宾斯基地毯目录一、题目内容:二、思路:三、python代码:4、总结一、题目内容:二、思路:看到这个图案,肯定是自相似的,所以肯定用递归解决这个问题。但是具体怎样的呢?(1)这个其实就是二维矩阵,所以是要判断每个位置是不是要填给定字符,如果确定了每个位置填或不填,那不就解决问题了嘛;(2)用两个for循环不就遍历了所有的位置了么,所以这个也简单,现在的难点在于如何知道每个位置要填,所以用一个函数判断;(3)这个判断的函数需要三个参数,一个是边长数,另外两个是坐标。边界条件是n=1就返回T.

    2022年7月13日
    17
  • laravel5.6 调用第三方类库

    laravel5.6 调用第三方类库

    2021年11月5日
    43

发表回复

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

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