golang 错误处理

2023-05-16

一、defer

package main

import (
	"fmt"
	"os"

	"bufio"
)

func tryDefer() {
	for i := 0; i < 100; i++ {
		defer fmt.Println(i)
		if i == 30 {
			// Uncomment panic to see
			// how it works with defer
			panic("printed too many")
		}
	}
}

func writeFile(filename string) {
	file, err := os.OpenFile(filename,
		os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666)

	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)
		}
		return
	}
	defer file.Close()//无论return、panic最后都会被执行

	writer := bufio.NewWriter(file)
	defer writer.Flush()//先进后执行,后进先执行,退出时先执行Flush,再执行Close

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

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

输出:

30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
panic: printed too many

goroutine 1 [running]:
main.tryDefer()
        /Users/jltxgcy/go/src/learn/errhandling/defer/defer.go:24 +0x111
main.main()
        /Users/jltxgcy/go/src/learn/errhandling/defer/defer.go:56 +0x20
defer执行的顺序是先进后执行,无论是提前return还是panic,defer都会执行,用于关闭资源等,通常是成对出现。

 

二、recovery

package main

import (
	"fmt"
)

func tryRecover() {
	defer func() {
		r := recover()
		if r == nil {
			fmt.Println("Nothing to recover. " +
				"Please try uncomment errors " +
				"below.")
			return
		}
		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(123)
		}
	}()

	// Uncomment each block to see different panic
	// scenarios.
	// Normal error
	panic(errors.New("this is an error"))

	// Division by zero
	//b := 0
	//a := 5 / b
	//fmt.Println(a)

	// Causes re-panic
	//panic(123)
}

func main() {
	tryRecover()
}

输出:

Error occurred: this is an error
打开:

b := 0
a := 5 / b
fmt.Println(a)

输出:

Error occurred: runtime error: integer divide by zero

打开:

panic(123)

输出:

panic: 123 [recovered]
        panic: I don't know what to do: 123

goroutine 1 [running]:
main.tryRecover.func1()
        /Users/jltxgcy/go/src/learn/errhandling/recover/recover.go:19 +0x1f6
panic(0x10ac4a0, 0x10eb4d0)
        /usr/local/go/src/runtime/panic.go:679 +0x1b2
main.tryRecover()
        /Users/jltxgcy/go/src/learn/errhandling/recover/recover.go:35 +0x5f
main.main()
        /Users/jltxgcy/go/src/learn/errhandling/recover/recover.go:39 +0x20
 

总结:

recover是用来接收panic的错误的,类似于try catch,用于捕捉panic的信息,不至于让panic输出信息那么难看。

如上panic(123),123并不是error类型,所以打印panic: I don't know what to do: 123。

 

三、错误处理实例

1、目录结构

filelistingserver(目录)

   filelisting(目录)     

     --handler.go

--web.go

handle.go

package filelisting

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

const prefix = "/list/"

type userError string//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 {
	fmt.Println()
	if strings.Index(
		request.URL.Path, prefix) != 0 {//localhost:8888/abc.txt,不以list开始
		return userError(
			fmt.Sprintf("path %s must start "+
				"with %s",
				request.URL.Path, prefix))
	}
	path := request.URL.Path[len(prefix):]
	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
}

web.go

package main

import (
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"

	"learn/errhandling/filelistingserver/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) {
		// panic
		defer func() {
			if r := recover(); r != nil {//统一处理panic
				log.Printf("Panic: %v", r)
				http.Error(writer,
					http.StatusText(http.StatusInternalServerError),
					http.StatusInternalServerError)
			}
		}()

		err := handler(writer, request)//HandleFileList

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

			// user error
			if userErr, ok := err.(userError); ok {//localhost:8888/abc.txt,不以/list开始
				http.Error(writer,
					userErr.Message(),
					http.StatusBadRequest)
				return
			}

			// system error
			code := http.StatusOK
			switch {
			case os.IsNotExist(err)://本地没有abc.txt
				code = http.StatusNotFound
			case os.IsPermission(err)://本地abc.txt没有权限访问
				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)
	}
}

启动server,在浏览器输入localserver:8888/list/abc.txt,就可以显示本地目录下的abc.txt。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

golang 错误处理 的相关文章

  • Golang教程:(十六)结构体

    原文 https golangbot com structs 欢迎来到Golang系列教程的第十六篇 什么是结构体 结构体 struct 是用户自定义的类型 它代表若干字段的集合 有些时候将多个数据看做一个整体要比单独使用这些数据更有意义
  • golang基础教程

    目录 golang基础教程 一 环境搭建 golang基础教程 二 开发规范及API golang基础教程 三 变量与数据类型概述 golang基础教程 四 基本数据类型 golang基础教程 五 基本数据类型的转换 golang基础教程
  • Go Web编程实战(6)----反射

    目录 反射 反射的3大原则 接口类型变量 转换为 反射类型对象 反射类型对象 转换为 接口类型变量 反射类型对象 修改 值必 可写的 反射 与其他语言一样 Go语言的反射同样是指 计算机程序在运行时 可以访问 检测和修改它本身状态或行为的一
  • Go项目部署及所遇问题

    小聊 本次小白给大家带来Golang项目部署操作以及个人所遇问题和解决它们的方法 依然是一边实操演示一边写文稿 如遇相似问题却存有疑惑可留言 开发环境是Window 部署环境是Linux 开发工具为GoLand 部署服务器为阿里云 1 打包
  • Go语言实现区块链与加密货币-Part3(交易优化,单机模拟多节点通信)

    交易 二 在这个系列文章的一开始 我们就提到了 区块链是一个分布式数据库 不过在之前的文章中 我们选择性地跳过了 分布式 这个部分 而是将注意力都放到了 数据库 部分 到目前为止 我们几乎已经实现了一个区块链数据库的所有元素 今天 我们将会
  • 带你使用Golang快速构建出命令行应用程序

    在日常开发中 大家对命令行工具 CLI 想必特别熟悉了 如果说你不知道命令工具 那你可能是个假开发 每天都会使用大量的命令行工具 例如最常用的Git Go Docker等 不管是做技术开发还是业务开发 都会有开发命令行程序的场景 例如如果是
  • Jenkins系列:3、wsl/ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序

    Jenkins系列 3 wsl ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序 文章目录 Jenkins系列 3 wsl ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序 1 前言 2 wsl
  • Go语言包管理(一)

    Go语言中的包 我们在使用其他语言 比如Java Python 都有类似包的概念 Go也不例外 其核心思想即为分组和模块化 人的大脑对庞大和复杂的事情很难掌控 可以对其采用分而治之的策略 使其模块化 从而更容易管理 如下是标准库中net包的
  • Golang 内存对齐视频

    https www bilibili com video BV1Ja4y1i7AF 简而言之 就是注意写代码的时候要把相同类型的元素放在一起 更进一步需要自己将结构体配对为32位或64位的整数倍 有助于减少额外空间消耗
  • Go 语言注释教程

    注释是在执行时被忽略的文本 注释可用于解释代码 使其更易读 注释还可用于在测试替代代码时防止代码执行 Go支持单行或多行注释 Go单行注释 单行注释以两个正斜杠 开头 在 和行尾之间的任何文本都将被编译器忽略 不会被执行 示例 This i
  • Go 程序编译过程(基于 Go1.21)

    版本说明 Go 1 21 官方文档 Go 语言官方文档详细阐述了 Go 语言编译器的具体执行过程 Go1 21 版本可以看这个 https github com golang go tree release branch go1 21 sr
  • 【go语言开发】编写单元测试

    本文主要介绍使用go语言编写单元测试用例 首先介绍如何编写单元测试 然后介绍基本命令的使用 最后给出demo示例 文章目录 前言 命令 示例 前言 在go语言中编写单元测试时 使用说明 测试文件命名 在 Go 语言中 测试文件的命名应与被测
  • go-zero开发入门-API服务开发示例

    接口定义 定义 API 接口文件 接口文件 add api 的内容如下 syntax v1 info title API 接口文件示例 desc 演示如何编写 API 接口文件 author 一见 date 2023年12月07日 vers
  • go-zero开发入门之gateway深入研究1

    创建一个 gateway 示例 main go package main import flag fmt gateway middleware github com zeromicro go zero core conf github co
  • go-zero 的 etcd 配置

    实现代码在 core discov config go 文件中 type EtcdConf struct Hosts string Key string ID int64 json optional User string json opt
  • “go mod tidy”之错误“not a valid zip file”

    执行 go mod tidy 时 遇到如下错误 rpc imports github com zeromicro go zero zrpc imports github com zeromicro go zero zrpc resolver
  • go语言实现文件夹上传前后端代码案例

    go语言实现文件夹上传前后端代码案例 前端用于上传的测试界面 如果上传的文件夹有子文件要遍历子文件夹创建出子文件夹再进行拷贝 需要获取文件名和对应的路径 将文件的相对路径和文件对象添加到FormData中 这几行代码很关键 for let
  • 【go语言】error错误机制及自定义错误返回类型

    简介 Go 语言通过内置的 error 接口来处理错误 该接口定义如下 type error interface Error string 这意味着任何实现了 Error 方法的类型都可以作为错误类型 在 Go 中 通常使用 errors
  • 这套Go语言开发框架组合真的非常高效

    我尝试过很多框架 从Django Flask和Laravel到NextJS和SvelteKit 到目前为止 这是我唯一可以使用的不会让我感到疯狂或者放弃项目的堆栈 框架 我喜欢所有这些框架 但我只是不太适应它们的设计方式 实际上 我是一个弱
  • 【go语言】结构体数据填充生成md错误码文件

    这里使用pongo2这个模版引擎库进行md文件渲染 GitHub flosch pongo2 Django syntax like template engine for Go package main import fmt github

随机推荐

  • CMake(六):使用子目录

    对于简单的项目 xff0c 将所有内容保存在一个目录中是可以的 xff0c 但是大多数实际项目倾向于将它们的文件分割到多个目录中 通常可以找到不同的文件类型或分组在各自的目录下的独立模块 xff0c 或者将属于逻辑功能组的文件放在项目目录层
  • CMake(九):生成器表达式

    当运行CMake时 xff0c 开发人员倾向于认为它是一个简单的步骤 xff0c 需要读取项目的CMakeLists txt文件 xff0c 并生成相关的特定于生成器的项目文件集 例如Visual Studio解决方案和项目文件 xff0c
  • CNNs系列---AlexNet网络介绍

    CNNs系列 AlexNet介绍 导言AlexNet介绍1 网络结构 1 参数量 计算量和输出尺寸计算公式 2 网络参数解析 2 AlexNet中涉及到的知识点 1 基本概念 2 AlexNet网络结构的贡献 导言 我们将开启关于卷积神经网
  • CNNS:基于AlexNet的分类任务

    CNNS 基于AlexNet的分类任务 数据集介绍1 pokeman数据集介绍2 flower数据集介绍 超参数对模型的影响1 激活函数对模型的影响 1 使用 96 Sigmoid 96 进行训练 2 使用 96 tanh 96 进行训练
  • CNNs: AlexNet补充

    CNNs AlexNet的补充 导言对 96 AlexNet 96 模型进行调整模型不同层的表征其他探索总结 导言 上上篇和上一篇我们详细地讲述了AlexNet的网络结构和不同超参数对同一数据集的不同实验现象 本节 xff0c 我们就Ale
  • 解决“Permission denied, please try again.”的问题

    在Ubuntu的终端输入命令 ssh highlight highlight是本地主机名称提示输入用户密码 当密码输入正确时 xff0c 仍返回错误 xff1a Permission denied please try again 解决的办
  • leetcode学习常用网站

    C 43 43 网站 cplusplus com map find C 43 43 Reference github com leopeng1995 acplusplus Morris Traversal方法遍历二叉树 xff08 非递归
  • arctan对照表

    注 xff1a 实际调用的是C 43 43 的atan2接口 arctan y x resultstd cout lt lt atan2 0 1 lt lt std endl 0std cout lt lt atan2 0 707 0 70
  • 关于optimized out

    根据网络上的说法 xff0c 调试期间如果一个变量的值显示 optimized out xff0c 那么就表明编译器将该变量进行了优化 xff0c 导致其值不可见 解决的方法是 xff0c 设置编译优化选项 xff0c 禁止相关的优化 可以
  • Ubuntu命令行中重复执行一个程序

    以下示例中 xff0c 执行program 10次 xff0c 并将运行日志以追加的方式重定向到log txt文件中 xff0c progam的入口参数是param for i in 1 10 do program param gt gt
  • 技术知识库

    我对自动控制技术发展趋势的理解 对数学理论的运用越来越深入 xff0c 对计算机的依赖越来越高 xff1b 与人们生产生活的契合越来越紧密以至于无法分割 xff1b 越来越向人类思维的本质倾向 心想事成靠拢 xff0c 让少数人的大脑和肢体
  • [AR论文阅读] Tracking Requirements for Augmented Reality

    论文作者 xff1a RONALD AZUMA年份 xff1a 1993论文主题 xff1a 阐述AR系统对6DoF跟踪性能的技术要求 要点 xff1a 三个核心要求 xff1a 高精度 xff0c 低延迟 xff0c 大范围 跟踪精度指标
  • cv::Mat和std::vector的相互转化

    声明 xff1a 代码来自StackOverFlow xff0c 原文链接 span class hljs keyword using span span class hljs keyword namespace span cv span
  • 构建fabMap过程中可能遇到的错误

    1 When OpenCV2 4 9 is not installed the system has OpenCV2 4 8 pre installed in usr lib x86 64 linux gnu and usr include
  • C++处理Ctrl+C中断信号

    span class hljs preprocessor include lt iostream gt span span class hljs preprocessor include lt csignal gt span span cl
  • Ubuntu获取最高权限(su)的方式

    sudo i span class hljs preprocessor 输入当前账户密码 span span class hljs preprocessor 进入su模式 xff08 root权限 xff09 span
  • 头文件被重复包含的危害及解决办法

    头文件被重复包含的危害 1 简单的理解 xff1a 无非就是头文件里有一行 int a 61 1 包含两次就变成了 int a 61 1 int a 61 1 于是变量重复定义 xff0c 报错 类 xff0c 函数同理 而当你写成 ifn
  • acrobat进行OCR文字识别失败

    OCR文字识别失败是因为pdf有一页图片过于华丽 xff0c 无法识别 xff0c 在adobe acrobat报错的时候 xff0c 瞅准这一页的页码 xff0c 然后跳过这一页 xff0c 继续文字识别其他页就可以了 黑底白字识别也会失
  • STL基础篇(适合初学者快速入门)

    1 STL 是什么 作为一个C 43 43 程序设计者 xff0c STL 是一种不可忽视的技术 Standard Template Library STL xff1a 标准模板库 更准确的说是 C 43 43 程序设计语言标准模板库 ST
  • golang 错误处理

    一 defer package main import 34 fmt 34 34 os 34 34 bufio 34 func tryDefer for i 61 0 i lt 100 i 43 43 defer fmt Println i