go基础笔记----错误处理与资源管理

文件目录结构

test.go

package main

import (
	"bufio"
	"fmt"
	"os"

	"./fib"
)

/*
	go语言资源管理

	1.go使用defer调用来实现资源管理{
		确保调用在函数结束发生的地方
		参数在defer语句时计算
		defer列表为先进后出
	}
	2.建了什么东西 都要想到defer掉{
		open/close
		lock/Unlock
		PrintHeader/PrintFooter
	}

	错误处理



*/

func tryDefer() {
	// defer里面有一个栈 多个语句先进后出 不怕中间出现return || panic
	defer fmt.Println(1)
	defer fmt.Println(2)
	fmt.Println(3)

	for i := 0; i < 100; i++ {
		defer fmt.Println(i)
		if i == 30 {
			panic("printed too many")
		}
	}
}

func writeFile(filename string) {
	file, err := os.Open(filename) // 新建文件要记住关掉 close()
	if err != nil {
		panic(err)
	}
	// err = errors.New("this is a custom error") // 自己新建error
	// if err != nil {
	// 	fmt.Println("Error: ", err)
	// 	if pathError, ok := err.(*os.PathError); !ok {
	// 		panic(err)
	// 	} else {
	// 		fmt.Println(pathError.Op, pathError.Path, pathError.Err)
	// 	}
	// 	return
	// }
	defer file.Close()

	writer := bufio.NewWriter(file) // 要flush
	defer writer.Flush()
	f := fib.Fib()
	for i := 0; i < 20; i++ {
		fmt.Fprintln(writer, f())
	}
}

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

web.go

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"./filelisting"
)

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) {

		defer func() {
			if r := recover(); r != nil {
				log.Printf("Panic: %v", r)
				http.Error(writer,
					http.StatusText(http.StatusInternalServerError),
					http.StatusInternalServerError)
			}
		}()

		err := handler(writer, request)
		if err != nil {
			log.Printf("Error handling request: %s", err.Error())

			if userErr, ok := err.(userError); ok {
				http.Error(writer,
					userErr.Message(),
					http.StatusBadRequest)
				return
			}

			code := http.StatusOK
			switch {
			case os.IsNotExist(err):
				code = http.StatusNotFound // 404
			case os.IsPermission(err):
				code = http.StatusForbidden // 403 没有权限
			default:
				code = http.StatusInternalServerError
			}
			http.Error(writer, http.StatusText(code), code)
		}
	}
}

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

	// panic(errors.New("this is an error"))
	// panic(123)
}

type userError interface {
	error
	Message() string
}

// 在url里面打一个文件地址 把文件内容显示出来
func main() {
	// tryRecover()
	http.HandleFunc("/",
		errWrapper(filelisting.HandleFileList))

	err := http.ListenAndServe(":8888", nil)
	if err != nil {
		panic(err)
	}
}

/*
	panic 遇到错误未知 不建议经常用{
		1.停止当前函数执行
		2.一直向上返回,执行每一层的defer
		3.如果没有遇见recover,程序退出
	}

	recover{
		仅在defer函数中调用
		获取panic的值
		如果无法处理,可以重新panic
	}
*/

/*
	error vs panic{
		1.意料之中的用error。如文件打不开
		2.意料之外的使用panic。如数组越界
	}

	案例总合使用{
		defer + panic + recover
		type Assertion
		函数式编程
	}

*/

handle.go

package filelisting

import (
	"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)
}

// HandleFileList http业务
func HandleFileList(writer http.ResponseWriter, request *http.Request) error {

	if strings.Index(request.URL.Path, prefix) != 0 {
		return userError("Path must start" + "with " + prefix)
	}

	path := request.URL.Path[len(prefix):] // /list/fib.txt 切片
	file, err := os.Open(path)
	if err != nil {
		return err
		// panic(err) // 如果出错 程序并不会挂掉 会被保护起来 recover会保护服务
	}
	defer file.Close()
	all, err := ioutil.ReadAll(file)
	if err != nil {
		return err
	}
	writer.Write(all)

	return nil
}

fib.go

package fib

// Fib 斐波那契数列
func Fib() func() int {
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return a
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值