本文同时发表在github.com/zhangyachen…
假设我们有如下结构体:
1 | 复制代码type User struct { |
我们需要对结构体内的字段进行验证合法性:
- Id的值在某一个范围内。
- Name的长度在某一个范围内。
- Email格式正确。
我们可能会这么写:
1 | 复制代码user := User{ |
这样的话代码比较冗余,而且如果结构体新加字段,还需要再修改验证函数再加一段if判断。这样代码比较冗余。我们可以借助golang的structTag来解决上述的问题:
1 | 复制代码type User struct { |
validate:"number,min=1,max=1000"
就是structTag。如果对这个比较陌生的话,看看下面这个:
1 | 复制代码 |
写过golang的基本都用过json:xxx
这个用法,json:xxx
其实也是一个structTag,只不过这是golang帮你实现好特定用法的structTag。而validate:"number,min=1,max=1000"
是我们自定义的structTag。
实现思路
我们定义一个接口Validator
,定义一个方法Validate
。再定义有具体意义的验证器例如StringValidator
、NumberValidator
、EmailValidator
来实现接口Validator
。
这里为什么要使用接口?假设我们不使用接口代码会怎么写?
1 | 复制代码if tagIsOfNumber(){ |
这样的话判断逻辑不能写在一个函数中,因为返回值validator会因为structTag的不同而不同,而且validator也不能当做函数参数做传递。而我们定义一个接口,所有的validator都去实现这个接口,上述的问题就能解决,而且逻辑更加清晰和紧凑。
关于接口的使用可以看下标准库的io Writer,Writer是个interface,只有一个方法Writer:
1 | 复制代码type Writer interface { |
而输出函数可以直接调用参数的Write方法即可,无需关心到底是写到文件还是写到标准输出:
1 | 复制代码func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { |
言归正传,我们看下完整代码,代码是Custom struct field tags in Golang中给出的:
1 | 复制代码package main |
代码很好理解,结构也很清晰,不做过多解释了^_^
github上其实已经有现成的验证包了govalidator,支持内置支持的验证tag和自定义验证tag:
1 | 复制代码package main |
参考资料:
本文转载自: 掘金