Skip to content

ErrorHandler 不接受指针类型 #5

Open

Description

@cgyy

Validate 和Error 对指针的处理方式不统一, 前者接受指针类型而后者不接受

// 这样的方法不被识别
func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {}

// macaron 识别这样的方法
func (form *VariantForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {}

Activity

  1. unknwon commented on Oct 26, 2015

    @unknwon
    Contributor

    func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {}

    不是很懂你这个方法是怎么来的。。

  2. cgyy commented on Oct 26, 2015

    @cgyy
    Author

    你好,是这样的
    比如我要自定义form的验证方法,可以这样写:

    func (form *MyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
    ///
    }

    也可以这样写

    func (form MyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
    ///
    }

    而自定义错误处理,只能写成这样:

    func (cf ContactForm) Error(ctx *macaron.Context, errs binding.Errors) {
        // 自定义错误处理过程
    }

    写成下面这样不起作用

    func (cf *ContactForm) Error(ctx *macaron.Context, errs binding.Errors) {
        // �自定义错误处理过程不起作用,
    }
  3. unknwon commented on Oct 26, 2015

    @unknwon
    Contributor

    能否发一下你绑定某个 form(不起作用的) 是怎么写的?

  4. cgyy commented on Oct 26, 2015

    @cgyy
    Author
    // 商品型号
    type VariantForm struct {
        OptionValues []int
        Price        float32 `binding:"Required"`
        Sku          string
    }
    
    // 验证选项值需要全部大于0
    func (form *VariantForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
        if len(errs) > 0 {
            return errs
        }
        for _, v := range form.OptionValues {
            if v == 0 {
                errs.Add([]string{"OptionValues"}, "RequiredError", "Required")
                break
            }
    
        }
        return errs
    }
    
    func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {
        if len(errs) > 0 {
            flash := ctx.GetVal(reflect.TypeOf(&session.Flash{})).Interface().(*session.Flash)
            errMsg := fmt.Sprintf("%s: %s", strings.Join(errs[0].FieldNames, ","), errs[0].Message)
            flash.Error(errMsg)
            ctx.Redirect(fmt.Sprintf("/variants/%d/edit", 30))
        }
    }

    自定义错误处理写成下面可以运行:

    func (form VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {
        if len(errs) > 0 {
            flash := ctx.GetVal(reflect.TypeOf(&session.Flash{})).Interface().(*session.Flash)
            errMsg := fmt.Sprintf("%s: %s", strings.Join(errs[0].FieldNames, ","), errs[0].Message)
            flash.Error(errMsg)
            ctx.Redirect(fmt.Sprintf("/variants/%d/edit", 30))
        }
    }
  5. unknwon commented on Oct 26, 2015

    @unknwon
    Contributor

    额。。其实我想说的是,注册路由部分的代码。。

  6. cgyy commented on Oct 27, 2015

    @cgyy
    Author

    好的,代码是这样的:

    type VariantsController struct {
        *macaron.Context
    }
    
    func MapVariants(ctx *macaron.Context) {
        ctx.Map(&VariantsController{ctx})
    }
    
        m.Group("/variants", func() {
            m.Get("/:id/edit", (*VariantsController).Edit)
            m.Put("/:id", binding.Bind(VariantForm{}), (*VariantsController).Update)
    
        }, MapVariants)
  7. unknwon commented on Oct 28, 2015

    @unknwon
    Contributor

    额。。看起来没问题。。我看了代码,判断 Validate 和 Error 的用法是一样的。。暂时不知道为什么。。0 0

  8. cgyy commented on Oct 28, 2015

    @cgyy
    Author

    似乎是Bind 方法里面没有判断指针类型的原因
    binding.go 104行

    func Bind(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
        return func(ctx *macaron.Context) {
            bind(ctx, obj, ifacePtr...)
            if handler, ok := obj.(ErrorHandler); ok {
                ctx.Invoke(handler.Error)
            } else {
                ctx.Invoke(errorHandler)
            }
        }
    }

    第210行

    func Validate(obj interface{}) macaron.Handler {
        return func(ctx *macaron.Context) {
            var errors Errors
            v := reflect.ValueOf(obj)
            k := v.Kind()
            if k == reflect.Interface || k == reflect.Ptr {
                v = v.Elem()
                k = v.Kind()
            }
            if k == reflect.Slice || k == reflect.Array {
                for i := 0; i < v.Len(); i++ {
                    e := v.Index(i).Interface()
                    errors = validateStruct(errors, e)
                    if validator, ok := e.(Validator); ok {
                        errors = validator.Validate(ctx, errors)
                    }
                }
            } else {
                errors = validateStruct(errors, obj)
                if validator, ok := obj.(Validator); ok {
                    errors = validator.Validate(ctx, errors)
                }
            }
            ctx.Map(errors)
        }
    }
  9. unknwon commented on Oct 29, 2015

    @unknwon
    Contributor

    噢。。那这个目前我还没想到什么好的办法,因为 Bind 是禁止你传指针的,否则会出现大量数据竞争破坏内存出现奇怪的错误

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions