go 验证字段 断言 以及反射的使用

代码问题

type ImageUpdateView struct {
	ID   uint   `json:"id" binding:"required" msg:"请选择文件id"`
	Name string `json:"name" binding:"required" msg:"请输入文件名称"`
}


	var cr ImageUpdateView
	err := c.ShouldBindJSON(&cr)

// GetValidMsg 返回结构体中的msg参数
func GetValidMsg(err error, obj any) string {
	//使用时,需要传obj的指针
	typeOf := reflect.TypeOf(obj)
	if errs, ok := err.(validator.ValidationErrors); ok {
		for _, e := range errs {
			//循环每一段错误信息
			//根据报错字段名.获取结构体的具体字段
			if fieldByName, exits := typeOf.Elem().FieldByName(e.Field()); exits {
				msg := fieldByName.Tag.Get("msg")
				return msg
			}
		}
	}
	return err.Error()
}

在 Go 中,断言(Assertion)通常指的是类型断言(Type Assertion),用于在运行时判断一个接口类型的值是否具有某种特定的类型

           value, ok := interfaceValue.(T)

  • interfaceValue: 需要断言的接口类型值。
  • T: 你想要将接口值断言成的目标类型。
  • value: 如果断言成功,value 将是 T 类型的值。
  • ok: 布尔值,表示断言是否成功。成功时,oktrue,否则为 false

举例

package main

import "fmt"

type Cat struct {
    Name string
}

type Dog struct {
    Name string
}

type Animal interface {
    Speak() string
}

func (c Cat) Speak() string {
    return "Meow"
}

func (d Dog) Speak() string {
    return "Woof"
}

func main() {
    var animal Animal

    animal = Cat{Name: "Tom"}

    // 使用类型断言来判断并访问具体类型
    if cat, ok := animal.(Cat); ok {
        fmt.Println("它是猫:", cat.Name)  // 输出: 它是猫: Tom
    } else {
        fmt.Println("它不是猫")
    }

    // 断言为 Dog 类型失败
    if dog, ok := animal.(Dog); ok {
        fmt.Println("它是狗:", dog.Name)
    } else {
        fmt.Println("它不是狗")  // 输出: 它不是狗
    }
}

接口使用的地方

// 使用时,需要传 obj 的指针

typeOf := reflect.TypeOf(obj)

  • reflect.TypeOf(obj): 获取 obj 的类型信息(reflect.Type 类型),用于后续操作。
  • 为什么需要传指针?
    • 如果传入的是结构体值,reflect.TypeOf(obj) 返回的类型信息无法获取到结构体字段的 tag,因为 tag 存在于类型本身,而不是值中。
    • 如果传入的是指针,使用 typeOf.Elem() 可以获取指针指向的结构体类型,从而访问字段信息。

    if errs, ok := err.(validator.ValidationErrors); ok {

  • err.(validator.ValidationErrors): 类型断言,将 err 转换为 validator.ValidationErrors 类型。
    • validator.ValidationErrorsvalidator 库中用于表示验证错误的类型,通常包含多个字段验证的错误信息。
  • if ... ok: 检查类型断言是否成功,只有当 errValidationErrors 类型时才会执行后续代码。

     for _, e := range errs {

  • for _, e := range errs: 遍历所有验证错误,每个错误存储在变量 e 中。
  • errs: 这是一个切片(或数组),每个元素都代表一个字段验证失败的信息。

            // 循环每一段错误信息
            // 根据报错字段名,获取结构体的具体字段
     if fieldByName, exits := typeOf.Elem().FieldByName(e.Field()); exits {

  • typeOf.Elem(): 如果 typeOf 是指针类型,Elem() 获取它指向的实际类型(即结构体类型)。
  • FieldByName(e.Field()): 使用验证错误中的字段名(e.Field()),获取结构体中对应的字段信息(reflect.StructField 类型)。
    • e.Field() 返回验证错误中涉及的字段名。
  • exits: 布尔值,表示字段是否存在。
    • 如果字段名在结构体中找不到,FieldByName 返回零值,exitsfalse

    msg := fieldByName.Tag.Get("msg")

  • fieldByName.Tag: 获取结构体字段的标签(reflect.StructTag 类型)。
  • Tag.Get("msg"): 从标签中提取 msg 的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值