golang 的 interface 的用法小妙招

6 篇文章 0 订阅

当我们在开发某个功能函数的时候,由于调用方的实参类型可能有多个,比如 beego 框架对 POST 请求的参数合法性的校验

func (c *BackupPlanNewController) ModifyBackupObjects(){
    .......
	var param msg.BackupObjectsPtr  //这可以是任何别的结构体,只要实现了 Valid 方法
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &param); err != nil {
		c.RenderFailResponse(400, err.Error())
		return
	}
	valid := validation.Validation{}
	b, err := valid.Valid(&param)
    ......
}

在 valid.Valid(&param) 函数里是怎么调用到 param 的 Valid 方法的,param 的类型可能是多种多样的。分析 valid.Valid 方法发现:

// Valid Validate a struct.
// the obj parameter must be a struct or a struct pointer
func (v *Validation) Valid(obj interface{}) (b bool, err error) {
	objT := reflect.TypeOf(obj)
	objV := reflect.ValueOf(obj)
	switch {
	case isStruct(objT):
	case isStructPtr(objT):
		objT = objT.Elem()
		objV = objV.Elem()
	default:
		err = fmt.Errorf("%v must be a struct or a struct pointer", obj)
		return
	}

	for i := 0; i < objT.NumField(); i++ {
		var vfs []ValidFunc
		if vfs, err = getValidFuncs(objT.Field(i)); err != nil {
			return
		}

		var hasRequired bool
		for _, vf := range vfs {
			if vf.Name == "Required" {
				hasRequired = true
			}

			currentField := objV.Field(i).Interface()
			if objV.Field(i).Kind() == reflect.Ptr {
				if objV.Field(i).IsNil() {
					currentField = ""
				} else {
					currentField = objV.Field(i).Elem().Interface()
				}
			}

			chk := Required{""}.IsSatisfied(currentField)
			if !hasRequired && v.RequiredFirst && !chk {
				if _, ok := CanSkipFuncs[vf.Name]; ok {
					continue
				}
			}

			if _, err = funcs.Call(vf.Name,
				mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil {
				return
			}
		}
	}

	if !v.HasErrors() {
		if form, ok := obj.(ValidFormer); ok {  //其实关键的就是这里的类型强转
			form.Valid(v)
		}
	}

	return !v.HasErrors(), nil
}

-------------------
// ValidFormer valid interface
type ValidFormer interface {
	Valid(*Validation)
}

可以看到关键的是把参数进行了一次类型强转,把 interface{} 转换为了 ValidFormer 接口就可以了,在以后的编码中可以借鉴下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值