Go语言开发小技巧&易错点100例(十二)

这篇具有很好参考价值的文章主要介绍了Go语言开发小技巧&易错点100例(十二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

往期回顾:

  • Go语言开发小技巧&易错点100例(一)
  • Go语言开发小技巧&易错点100例(二)
  • Go语言开发小技巧&易错点100例(三)
  • Go语言开发小技巧&易错点100例(四)
  • Go语言开发小技巧&易错点100例(五)
  • Go语言开发小技巧&易错点100例(六)
  • Go语言开发小技巧&易错点100例(七)
  • Go语言开发小技巧&易错点100例(八)
  • Go语言开发小技巧&易错点100例(九)
  • Go语言开发小技巧&易错点100例(十)
  • Go语言开发小技巧&易错点100例(十一)

本期看点(技巧类用【技】表示,易错点用【易】表示)

  • Go HTTP全局异常处理器【技】
  • Go反射【技】

正文开始:

Go HTTP全局异常处理器

在Go语言中,使用net/http包构建HTTP服务器时,全局异常处理器通常指的是一个中间件,它可以捕获所有未被其他处理程序捕获的异常,并对它们进行统一的错误处理。这包括HTTP响应错误(如404 Not Found或500 Internal Server Error)以及可能的panic错误。

下面是一个如何实现全局异常处理器的例子:

package main

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

// 全局异常处理器
func globalErrorHandler(err error, w http.ResponseWriter, r *http.Request) {
	// 记录错误信息
	log.Printf("Error: %v", err)

	// 设置HTTP状态码
	if httpErr, ok := err.(*http.Error); ok {
		w.WriteHeader(httpErr.Code)
	} else {
		w.WriteHeader(http.StatusInternalServerError)
	}

	// 返回错误消息给客户端
	w.Write([]byte(err.Error()))
}

// 自定义HTTP错误处理函数
func handleError(w http.ResponseWriter, r *http.Request, err error) {
	// 在这里你可以根据需要对错误进行特殊处理
	// 如果没有特殊处理,则调用全局异常处理器
	globalErrorHandler(err, w, r)
}

// 示例HTTP处理函数
func helloHandler(w http.ResponseWriter, r *http.Request) {
	// 示例:故意制造一个错误
	panic("Something went wrong!")
}

func main() {
	// 设置自定义错误处理函数
	http.DefaultServeMux.HandleFunc("/", helloHandler)
	http.DefaultServeMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("OK"))
	})

	// 使用自定义错误处理函数作为全局异常处理器
	http.DefaultServeMux.HandlerFunc("/global-error-handler").Func = func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				handleError(w, r, err)
			}
		}()
		http.NotFound(w, r)
	}

	fmt.Println("Server is running at http://localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

在上面的例子中,globalErrorHandler 函数被设计为一个通用的错误处理器,它可以处理由handleError函数传递过来的错误。而handleError函数则作为一个桥接器,它既可以被直接调用,也可以在需要捕获panic的地方被defer语句调用。

helloHandler函数故意制造了一个panic错误,这个错误会被defer捕获,并传递给handleError函数,最后由globalErrorHandler统一处理。

需要注意的是,在真实的应用中,全局异常处理器可能需要处理更多种类的错误,包括自定义错误、第三方库错误等。此外,对于大型应用,通常会使用更复杂的错误处理机制,如错误包装(error wrapping)和日志记录(logging)等。

此外,如果你使用的是像Gin这样的Web框架,它们通常有自己的中间件机制来处理全局异常,这样可以使错误处理更加灵活和强大。

Go反射

在Go语言的编程世界中,反射(Reflection)是一个强大的工具,它允许程序在运行时检查、修改和调用对象的类型和值。虽然反射提供了极大的灵活性,但也需要谨慎使用,因为它可能会破坏封装性并降低性能。在本文中,我们将深入了解Go语言的反射机制,探讨其用法、优点和潜在陷阱。

一、什么是反射?

反射是一种在运行时检查、修改和调用对象类型和值的能力。在Go语言中,reflect 包提供了反射功能。通过反射,我们可以获取一个接口值(interface{})所表示的具体类型信息,以及该类型的值。

二、反射的基本用法

  1. 获取类型信息: 使用 reflect.TypeOf() 函数可以获取一个值的类型信息。
x := 42
t := reflect.TypeOf(x)
fmt.Println(t) // 输出: int
  1. 获取值信息: 使用 reflect.ValueOf() 函数可以获取一个值的反射对象,然后可以进一步获取或修改该值。
v := reflect.ValueOf(x)
fmt.Println(v.Int()) // 输出: 42
  1. 调用方法: 通过反射对象的 MethodByName() 方法,我们可以调用一个对象的方法。
type MyStruct struct {
    Name string
}

func (m *MyStruct) SayHello() {
    fmt.Println("Hello, my name is", m.Name)
}

ms := &MyStruct{Name: "Alice"}
method := reflect.ValueOf(ms).MethodByName("SayHello")
method.Call(nil) // 输出: Hello, my name is Alice
  1. 其他:
type Student struct {
   Id   int64
   Name string
   Age  int
}

func TestStruct(t *testing.T) {
   stu := Student{1, "zs", 12}
   obj := reflect.ValueOf(stu)
   field := obj.FieldByName("Name")
   field1 := obj.Field(0)
   num := obj.NumField()
   fmt.Println("字段数量:", num)
   fmt.Println("Name字段的值:", field)
   fmt.Println("第0个字段的值:", field1)
   obj1 := reflect.ValueOf(new(Student))
   addr := obj1.CanAddr() //是否能寻址
   if addr {
      fmt.Println(obj1.Addr())
   }
}

// 切片类型的反射
func TestSlice(t *testing.T) {
   slice := make([]int, 10)
   s := reflect.ValueOf(slice)
   //加入元素
   s.Index(0).Set(reflect.ValueOf(100))
   //获取元素
   i := s.Index(0).Interface()
   fmt.Println(slice)
   fmt.Println(i)
}

// Map类型的反射
func TestMap(t *testing.T) {
   m := make(map[string]interface{})
   m["A"] = 1
   m["B"] = 2
   m["C"] = 3
   mv := reflect.ValueOf(m)
   //赋值
   mv.SetMapIndex(reflect.ValueOf("D"),reflect.ValueOf(4))
   iter := mv.MapRange()
   keys := mv.MapKeys()
   fmt.Println(keys)
   for iter.Next() {
      fmt.Println(iter.Value())
   }
}

func TestReflection(t *testing.T) {
   var x float64 = 3.4
   v := reflect.ValueOf(x)
   //v.SetFloat(7.1) // Error: will panic.

   p:= reflect.ValueOf(&x)

   v1 := p.Elem()
   fmt.Println("settability of v:", v1.CanSet())
   v1.SetFloat(7.1)
   fmt.Println(v.Interface())
   fmt.Println(x)
}

三、反射的优点

  1. 灵活性: 反射允许我们在运行时动态地操作对象,这为编写通用代码和库提供了极大的便利。
  2. 调试和测试: 反射可以用于在运行时检查对象的状态,这对于调试和测试非常有用。

四、反射的潜在陷阱

  1. 性能损失: 反射操作通常比直接操作要慢得多,因为它们涉及到运行时类型信息的查找和值的间接访问。
  2. 破坏封装性: 过度使用反射可能会破坏代码的封装性,使得代码难以理解和维护。
  3. 类型安全: 由于反射允许我们绕过类型检查,因此可能导致类型错误或运行时错误。

五、何时使用反射?

虽然反射提供了强大的功能,但在大多数情况下,我们应该避免使用它。以下是一些使用反射的合理场景:

  1. 编写通用代码: 当我们需要编写处理不同类型数据的通用函数时,反射是一个很好的选择。
  2. 序列化和反序列化: 在实现自定义的序列化和反序列化逻辑时,反射可以帮助我们动态地处理不同类型的数据。
  3. 框架和库开发: 在开发框架和库时,反射可以帮助我们实现更灵活和可扩展的功能。

六、总结

Go语言的反射机制为我们提供了在运行时检查和操作对象类型和值的强大能力。然而,它也有一些潜在的陷阱和限制。因此,在使用反射时,我们需要权衡其优点和缺点,谨慎地选择何时使用它。在大多数情况下,我们应该优先使用静态类型检查和直接操作来保持代码的清晰、高效和类型安全。文章来源地址https://www.toymoban.com/news/detail-827855.html

到了这里,关于Go语言开发小技巧&易错点100例(十二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C语言易错点】循环结构

    C语言的循环结构是一种控制结构,用于重复执行一段代码,直到满足某个条件为止。C语言提供了三种主要的循环结构:for循环、while循环和do-while循环。 for循环: for循环具有以下形式: 其中,初始化表达式在循环开始前执行一次,用于初始化循环控制变量;循环条件判断是

    2024年02月04日
    浏览(27)
  • C语言初学习——易错点合集(持续更新中)

    转义字符 例题一 输出: —— n=3 —— 例题二 输出: —— 1 13 14 —— 总结: 八进制值的判断取决于后续是否为合法的八进制。 以开始,最少1位,最多3位,且必须是合法的8进制数字,即0~7,如\\\"\\012\\\"。 例:在\\\"\\08\\\"中,’\\0’为结束符。 自增与自减 例题一 输出: —— 死循环

    2024年03月09日
    浏览(60)
  • 全面理解链表数据结构:各种节点操作、做题技巧,易错点分析与题目清单(C++代码示例,不断更新)

    链表是一种线性数据结构,它包含的元素并不是物理上连续的,而是通过指针进行连接。链表中的每个元素通常由一个节点表示,每个节点包含一个数据元素和一个或多个链接(指针)。 链表的主要类型包括: 单向链表 (Singly Linked List):每个节点包含一个指向下一个节点

    2024年02月07日
    浏览(30)
  • 初始C语言——详细讲解操作符以及操作符的易错点

     第一章 “C“浒传——初识C语言(更适合初学者体质哦!)  第二章 详细认识分支语句和循环语句以及他们的易错点   第三章 初阶C语言——特别详细地介绍函数  第四章 初始C语言——详细地讲解数组的内容以及易错点  第五章  初始C语言——详细讲解操作符以及操

    2024年02月13日
    浏览(43)
  • 初始C语言(6)——详细讲解表达式求值以及其易错点

     第一章 “C“浒传——初识C语言(1)(更适合初学者体质哦!)  第二章 初始C语言(2)——详细认识分支语句和循环语句以及他们的易错点   第三章 初阶C语言(3)——特别详细地介绍函数  第四章 初始C语言(4)——详细地讲解数组的内容以及易错点  第五章 初

    2024年02月12日
    浏览(31)
  • 【初始C语言2】详细认识分支语句和循环语句以及他们的易错点,应用(猜大小游戏)

    系列文章目录  第一章 “C“浒传——初识C语言(更适合初学者体质哦!)  第二章  【初始C语言2】详细认识分支语句和循环语句以及他们的易错点,应用(猜大小游戏) 目录 系列文章目录 前言:        一、什么是语句? 1.1 表达式语句 1.2 函数调用语句 1.3 控制语句

    2024年02月10日
    浏览(32)
  • 100天精通Golang(基础入门篇)——第23天:错误处理的艺术: Go语言实战指南

    🌷🍁 博主猫头虎🐅🐾 带您进入 Golang 语言的新世界✨✨🍁 🦄 博客首页 ——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》 🐾 学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通

    2024年02月07日
    浏览(54)
  • 100天精通Golang(基础入门篇)——第5天: Go语言中的数据类型学习

    🌷 博主 libin9iOak带您 Go to Golang Language.✨ 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批

    2024年02月08日
    浏览(36)
  • 数据结构-----树的易错点

    1.树的度和m叉树 •度为m的树(度表示该结点有多少个孩子(分支)) 任意结点的度=m(最多m个孩子) 至少又一个结点度=m(有m个孩子) 一定是非空树,至少有m+1个结点 •m叉树 任意结点的度=m(最多有m个孩子) 允许所有结点的度都m 可以是空树 2. m叉树 第i层至多有个结点 或度为

    2024年02月11日
    浏览(23)
  • Egg - 中间件易错点和洋葱模型

    废话不多说,我给大家写个 Demo : 伪代码很简单,意思就是: 如果用户没有权限,返回一个固定的 Code 。 如果有权限则放行。 这段代码从语义上看其实并没有任何问题,用过 Egg 的小伙伴也知道, 给 ctx.body 对象赋值,也相当于给最终返回对象赋值。 但是这个代码却有着很

    2024年02月13日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包