1、错误记录
go版本:
GOVERSION="go1.16.4"
通过 reflect 调用 struct 实现的方法,给方法传递参数时,报错。记录下。
报错原因:
panic: reflect: Call with too few input arguments
报错代码:
// tmpS 是一个结构体
t := reflect.TypeOf(&tmpS)
v := reflect.ValueOf(&tmpS)
for i:=0; i < v.NumMethod(); i++ {
if t.Method(i).Name == "Verify" {
continue
}
m, ok := t.MethodByName(t.Method(i).Name)
if !ok {
continue
}
var args = []reflect.Value{
reflect.ValueOf(tmpData[t.Method(i).Name]),
}
tmp := m.Func.Call(args)
result += tmp[0].String()
}
解决办法:
var args = []reflect.Value{
reflect.ValueOf(&tmpS), // 这里要加这个,否则报错
reflect.ValueOf(tmpData[t.Method(i).Name]),
}
tmp := m.Func.Call(args)
2、需求简介
现有一个功能,不同类型的主机上面,需要定时采集需要的数据,然后上报给后台服务,后台服务检查数据是否达到了验收标准。需要将上报数据验收的结果在前端展示,这样才方便管理。
比如,有两种类型的主机,上报的数据不同。
- t1 类型的数据
{
"name": "t1",
"memory": 68,
"hostname": "t1-112-113"
}
- t2 类型的数据
{
"name": "t2",
"disk": 512,
"hostname": "t2-112-114"
}
根据 name 的不同,验收上报的数据,是否到达了验收标准。
3、实现
后台是使用 gin 来开发的,这里主要记录下如何实现验收这部分功能。代码如下(仅仅是演示):
- 所有上报类型的数据,比如这里的 Seal,都需要实现 AutoCheckImpl 接口。
- Verify 方法里面根据传递进来的数据,来实现验证功能。
实现的方式不够优雅,以后有更好的实现方式了再来更新,要是你有更好的方法,麻烦告知下,学习学习(哈哈…)
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type AutoCheckImpl interface {
Verify(data string) string
}
type Base struct {
Name string `json:"name"`
}
func (b *Base) VerifyHostname(param interface{}) string {
fmt.Println("VerifyHostname")
return ""
}
type Seal struct {
Hostname string `json:"hostname"`
Memory float64 `json:"memory"`
}
// 确保 Seal 实现了 AutoCheckImpl 的方法
// var _ AutoCheckImpl = new(Seal)
//var _ AutoCheckImpl = (*Seal)(nil)
func (s *Seal) Verify(data string) string {
var result string
var tmpS Seal
err := json.Unmarshal([]byte(data), &tmpS)
tmpData := map[string]interface{}{
"VerifyHostname": tmpS.Hostname,
"VerifyMemory": tmpS.Memory,
}
if err != nil {
return fmt.Sprintf("Seal Verify Unmarshal failed, %s", err)
}
t := reflect.TypeOf(&tmpS)
v := reflect.ValueOf(&tmpS)
for i:=0; i < v.NumMethod(); i++ {
if t.Method(i).Name == "Verify" {
continue
}
m, ok := t.MethodByName(t.Method(i).Name)
if !ok {
continue
}
var args = []reflect.Value{
reflect.ValueOf(&tmpS), // 这里要加这个,否则报错
reflect.ValueOf(tmpData[t.Method(i).Name]),
}
tmp := m.Func.Call(args)
result += tmp[0].String()
}
return result
}
func (s *Seal) VerifyMemory(mem float64) string {
fmt.Println("Seal VerifyMemory ")
if mem <= 64 {
return "内存不足"
}
return ""
}
func NewFactory(name string) AutoCheckImpl {
if name == "seal" {
return &Seal{}
}
return nil
}
func main() {
data := `
{
"name": "seal",
"memory": 68,
"hostname": "se-112-113"
}
`
var b Base
err := json.Unmarshal([]byte(data), &b)
if err != nil {
fmt.Println("Unmarshal failed, ", err)
return
}
f := NewFactory(b.Name)
if len(f.Verify(data)) >= 1 {
fmt.Println("验证未通过")
} else {
fmt.Println("验证通过")
}
}