Golang Interface
目录
接口的定义
interface
是一组 method
的集合。接口做的事情就像是定义一个协议(规则)。不关心属性(数据),只关心行为(方法)。
接口(interface)是一种类型!
type MyInterface interface{
FunctionOne(interface{})(interface{})
FunctionTow(data string)(bool)
}
接口中定义的函数,参数列表和返回值列表中的变量名都可以省略!
接口可以嵌套
type Sayer interface{
say()
}
type Mover interface{
move()
}
type People interface{
Sayer
Mover
}
实现接口的条件
一个对象只要全部实现了接口中的方法,那么就实现了这个接口。也就是说: 接口是一个需要实现的一系列方法的列表。
重要!
值接收者和指针接收者接口实现接口是有区别的!
- 值接收者实现的接口不管是
结构体
、还是结构体指针
都能赋值给对应实现的接口变量(这是因为Go中有对指针类型变量求值的语法糖,结构体指针
内部会自动求值*结构体指针
- 指针类型接收者实现的接口只能传递
*结构体
类型值赋值给接口
下面的验证类接口中有具体指针类型接收者实现接口的例子。
接口的用途
列子
编写验证数字和字符串长度的类
- main.go
package main
import (
"demo/validate"
"fmt"
)
type user struct {
Name string `valida:"required,min=22,max=100"`
Password string `valida:"-"`
Age int `valida:"required,min=1,max=120"`
}
func main() {
u := user{
Name: "Hello",
Password: "Password",
Age: 1,
}
v := validate.NewValidate(u)
v.Validate()
for _, err := range v.Error {
fmt.Println(err)
}
}
- validate.go
package validate
import (
"fmt"
"reflect"
"strconv"
"strings"
)
const validatorTagName = "valida"
type Validate struct {
Data interface{}
Error []error
}
func NewValidate(data interface{}) *Validate {
return &Validate{Data: data}
}
func (v *Validate) Validate() {
var errs []error
valueOf := reflect.ValueOf(v.Data)
//只支持结构体验证
if valueOf.Kind() != reflect.Struct {
panic("只支持struct类型验证")
}
//循环结构体,获取每一行的相关属性
for i := 0; i < valueOf.NumField(); i++ {
//获取对应的tag数据
tag := valueOf.Type().Field(i).Tag.Get(validatorTagName)
//获取对应类型的数据类(其实是一个验证类接口的实例化)
validate := v.getValidate(valueOf.Field(i).Kind().String(), valueOf.Type().Field(i).Name, tag)
//实例化的验证类开始验证数据
validator, err := validate.Validator(valueOf.Field(i).Interface())
if !validator && err != nil {
errs = append(errs, err)
}
}
v.Error = errs
}
// 不能返回指针类型接口 结构体是指针类型的实现,需要访问结构体指针类型的值
// 指针类型接收者实现的接口只能传递`*结构体`类型值赋值给接口
func (v *Validate) getValidate(fieldType, fieldName, tag string) Validator {
tagArgs := strings.Split(tag, ",")
//过滤不需要验证的字段
if tagArgs[0] == "-" || tagArgs[0] == "" {
return &DefaultValidator{}
}
switch fieldType {
case "string":
strValidator := &StringValidator{}
strValidator.FieldName = fieldName
for _, val := range tagArgs {
if val == "required" {
strValidator.Required = true
}
if strings.Contains(val, "min") {
valArgs := strings.Split(val, "=")
strValidator.Min, _ = strconv.Atoi(valArgs[1])
}
if strings.Contains(val, "max") {
valArgs := strings.Split(val, "=")
strValidator.Max, _ = strconv.Atoi(valArgs[1])
}
}
if strValidator.Max < strValidator.Min {
panic("max value must be greater than min value!")
}
return strValidator
case "int":
intValidator := &IntValidator{}
intValidator.FieldName = fieldName
for _, val := range tagArgs {
if val == "required" {
intValidator.Required = true
}
if strings.Contains(val, "min") {
valArgs := strings.Split(val, "=")
intValidator.Min, _ = strconv.Atoi(valArgs[1])
}
if strings.Contains(val, "max") {
valArgs := strings.Split(val, "=")
intValidator.Max, _ = strconv.Atoi(valArgs[1])
}
}
if intValidator.Min > intValidator.Max {
panic("max value must be greater than min value!")
}
return intValidator
}
return &DefaultValidator{}
}
//验证类接口
type Validator interface {
Validator(interface{}) (bool, error)
}
type DefaultValidator struct{}
type StringValidator struct {
FieldName string
Max, Min int
Required bool
}
type IntValidator struct {
FieldName string
Max, Min int
Required bool
}
func (d *DefaultValidator) Validator(interface{}) (bool, error) {
return true, nil
}
func (s *StringValidator) Validator(data interface{}) (bool, error) {
str := data.(string)
length := len(str)
if s.Required && length == 0 {
return false, fmt.Errorf("%s 为必填字段", s.FieldName)
}
if length < s.Min {
return false, fmt.Errorf("%s 长度不能小于 %d", s.FieldName, s.Min)
}
if length > s.Max {
return false, fmt.Errorf("%s 长度不能大于 %d", s.FieldName, s.Max)
}
return true, nil
}
func (i *IntValidator) Validator(data interface{}) (bool, error) {
integer := data.(int)
if i.Required && integer == 0 {
return false, fmt.Errorf("%s 不能为0", i.FieldName)
}
if integer < i.Min {
return false, fmt.Errorf("%s 不能小于 %d", i.FieldName, i.Min)
}
if integer > i.Max {
return false, fmt.Errorf("%s 不能大于 %d", i.FieldName, i.Max)
}
return true, nil
}
接口断言
函数的参数是空接口时可以使用断言来获取实际传入的数据
func main {
var x interface{}
x = "Hello Golang"
v,ok := x.(string)
if ok {
fmt.Println(v)
else{
fmt.Println("不是string类型")
}
}
阅读其他文章