美文网首页GO
GO: 接口和反射应用

GO: 接口和反射应用

作者: 随风化作雨 | 来源:发表于2017-12-19 12:19 被阅读14次
package main

import (
    "fmt"
    "reflect"
    "regexp"
    "strings"
)

const tagName = "validate"

//邮箱验证
var mailRe = regexp.MustCompile(`\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z`)

//验证接口
type Validator interface {
    Validate(interface{}) (bool, error)
}

type DefaultValidator struct{}

func (v DefaultValidator) Validate(val interface{}) (bool, error) {
    return true, nil
}

type StringValidator struct {
    Min int
    Max int
}

func (v StringValidator) Validate(val interface{}) (bool, error) {
    l := len(val.(string))
    if l == 0 {
        return false, fmt.Errorf("cannot be blank")
    }
    if l < v.Min {
        return false, fmt.Errorf("should be at least %v chars long", v.Min)
    }
    if v.Max >= v.Min && l > v.Max {
        return false, fmt.Errorf("should be less than %v chars long", v.Max)
    }
    return true, nil
}

type NumberValidator struct {
    Min int
    Max int
}

func (v NumberValidator) Validate(val interface{}) (bool, error) {
    num := val.(int)
    if num < v.Min {
        return false, fmt.Errorf("should be greater than %v", v.Min)
    }
    if v.Max >= v.Min && num > v.Max {
        return false, fmt.Errorf("should be less than %v", v.Max)
    }
    return true, nil
}

type EmailValidator struct{}

func (v EmailValidator) Validate(val interface{}) (bool, error) {
    if !mailRe.MatchString(val.(string)) {
        return false, fmt.Errorf("is not a valid email address")
    }
    return true, nil
}

func getValidatorFromTag(tag string) Validator {
    args := strings.Split(tag, ",")
    switch args[0] {
    case "number":
        validator := NumberValidator{}
        fmt.Sscanf(strings.Join(args[1:], ","), "min=%d,max=%d", &validator.Min, &validator.Max)
        return validator
    case "string":
        validator := StringValidator{}
        fmt.Sscanf(strings.Join(args[1:], ","), "min=%d,max=%d", &validator.Min, &validator.Max)
        return validator
    case "email":
        return EmailValidator{}
    }
    return DefaultValidator{}
}

func validateStruct(s interface{}) []error {
    errs := []error{}
    v := reflect.ValueOf(s)
    for i := 0; i < v.NumField(); i++ {
        tag := v.Type().Field(i).Tag.Get(tagName)
        if tag == "" || tag == "-" {
            continue
        }
        validator := getValidatorFromTag(tag)
        valid, err := validator.Validate(v.Field(i).Interface())
        if !valid && err != nil {
            errs = append(errs, fmt.Errorf("%s %s", v.Type().Field(i).Name, err.Error()))
        }
    }
    return errs
}

type User struct {
    Id    int    `validate:"number,min=1,max=1000"`
    Name  string `validate:"string,min=2,max=10"`
    Bio   string `validate:"string,min=2,max=10"`
    Email string `validate:"email"`
}

func main() {
    user := User{
        Id:    0,
        Name:  "superlongstring",
        Bio:   "superlongstring",
        Email: "foobar",
    }
    fmt.Println("Errors:")
    for i, err := range validateStruct(user) {
        fmt.Printf("\t%d. %s\n", i+1, err.Error())
    }
}

相关文章

  • GO: 接口和反射应用

  • go学习-接口和反射

    1、接口和它的实现 可以不在一个包里,也无先后顺序之分; 2、类型的实例可以赋值给接口的实例,如果该接口有方法集,...

  • golang

    一、go基础 二、go应用 1 初级应用 1.1. 反射reflection 1.2. server服务 1.3....

  • reflect.go包学习_之二 指针操作提高反射性能 反射应用

    reflect.go包学习_之二 指针操作提高反射性能 反射应用 反射创建实例 反射信息、反射调用方法、反射修改值...

  • go接口与反射

    go语言的interface是个很松散的概念,类型不必明确声明实现了接口,go语言通过内部维护一个实现此接口方法的...

  • go 反射

    反射的概念 反射就是程序能够在运行时动态的查看自己的状态,比关切允许修改自身的行为。1、GO的反射基础是接口和类型...

  • 第05天(异常、文本文件处理)_01

    01_error接口的使用.go 02_error接口应用.go 03_显式调用panic函数.go 04_数组越...

  • 《Go语言四十二章经》第二十七章 反射(reflect)

    《Go语言四十二章经》第二十七章 反射(reflect) 作者:李骁 27.1 反射(reflect) 反射是应用...

  • Go语言探索 - 12(结局)

    Go语言基础系列博客用到的所有示例代码 上一篇文章文章主要学习了Go语言中的接口、反射以及错误和异常处理。本篇文章...

  • reflect使用

    reflect概述 反射是一种检查存储在 接口变量中的<值,类型>对 的机制,借助go反射包提供的reflect....

网友评论

    本文标题:GO: 接口和反射应用

    本文链接:https://www.haomeiwen.com/subject/xrubwxtx.html