Reflection Go:reflect:Call的输入参数太少

Reflection Go:reflect:Call的输入参数太少,reflection,go,Reflection,Go,我遇到了使用反射库的问题。我想用它是因为有很多建议,但我只是在学习围棋,有些地方并不容易 我有这部分代码: func countDataByName(sourceName string, statData interface{}, filters Filter, chartName string) []ChartElement { ... //step 1 - filter filteredData := reflect.ValueOf(statData

我遇到了使用反射库的问题。我想用它是因为有很多建议,但我只是在学习围棋,有些地方并不容易

我有这部分代码:

 func countDataByName(sourceName string, statData interface{}, filters Filter, chartName string) []ChartElement {
            ...
    //step 1 - filter
    filteredData := reflect.ValueOf(statData).MethodByName("FilterData").Call([]reflect.Value{})

    //step 2 - cluster
    //  clusterData := reflect.ValueOf(filteredData).MethodByName("clusterData").Call([]reflect.Value{})

    //step 3 - count
    //  countedData := reflect.ValueOf(clusterData).MethodByName(chartName).Call([]reflect.Value{})

    fmt.Println("Never prints to anywhere", filteredData)

            ...
     return filterData
 }
如果像这样执行该方法,则会出现错误:
reflect:Call,输入参数太少
。但是如果我在
reflect.ValueOf(&statData)
上更改
reflect.ValueOf(statData)
,则错误为
reflect:call of reflect.Value.call on zero Value

statData
提供了两种类型中的一种,对于这两种类型,我有如下结构和方法:

type NoaggModel struct {
    Date             string
    Hour             int
    Id_user          int
    Id_line          int
    Id_region        int
    Id_tree_devision int
    N_inb            int
    N_inb_d          int
    T_ring           int
    T_inb            int
    T_inb_d          int
    T_hold           int
    T_acw            int
    T_acw_d          int
    T_wait           int
}

func (ng *NoaggModel) FilterData( data NoaggModel) {
    fmt.Println("FilterData")
    fmt.Println("data : ", data)
}
    ...
    var sourceTypes = map[string]reflect.Type{
        "noagg": reflect.TypeOf(models.NoaggModel{}),
        "oracle": reflect.TypeOf(models.OracleModel{}),
    }
    deserializedData = reflect.New(sourceTypes[sourceName]).Interface()
    ...
    // deserialised becomes statData
这个Println也不起作用。上面的代码恐慌,方法未被触发。我的错在哪里

Upd 1:

发现如果我在我要调用的function中删除param
data
,它会很好地调用。但是 我有
statData
作为一行结构,所以类型是
NoaggModel
。在方法
FilterData
中,我得到这1行作为
ng
。但我需要将其更改为
[]NoaggModel
。在这种情况下,如何调用
reflect
,以及如何将参数传递给filter函数

Upd 2: 我修改了几个部分:

func (ng *NoaggModel) FilterData(filter interface{}, data NoaggModel) {
    fmt.Println("data : ",ng)
}
在这里,如果在revel controller中设置了正确的类型,并且方法在模型中,则如何将正确的类型传递给过滤器。或者我应该在每个模型中设置类型并在控制器中调用它

我在《控制器》中写道:

//step 1 - filter
    in := make([]reflect.Value, 2)

    in[0] = reflect.ValueOf(filters)
    in[1] = reflect.ValueOf(statData)

    filteredData := reflect.ValueOf(statData).MethodByName("FilterData").Call(in)
StatData
是NoaggModel类型的一行,但我得到了错误:

 reflect: Call using *models.NoaggModel as type models.NoaggModel 
类型也是由上面代码中的
reflect
设置的,如下所示:

type NoaggModel struct {
    Date             string
    Hour             int
    Id_user          int
    Id_line          int
    Id_region        int
    Id_tree_devision int
    N_inb            int
    N_inb_d          int
    T_ring           int
    T_inb            int
    T_inb_d          int
    T_hold           int
    T_acw            int
    T_acw_d          int
    T_wait           int
}

func (ng *NoaggModel) FilterData( data NoaggModel) {
    fmt.Println("FilterData")
    fmt.Println("data : ", data)
}
    ...
    var sourceTypes = map[string]reflect.Type{
        "noagg": reflect.TypeOf(models.NoaggModel{}),
        "oracle": reflect.TypeOf(models.OracleModel{}),
    }
    deserializedData = reflect.New(sourceTypes[sourceName]).Interface()
    ...
    // deserialised becomes statData

反思并不容易。如果可能的话应该避免

我承认,我确实建议使用
reflect
根据映射动态创建类型实例,这在您不知道可能需要处理哪些类型时非常有用。但是在你的情况下,你应该考虑使用接口。 虽然我真的不知道您想要实现什么,但我建议您首先创建一个所有模型都需要实现的接口(修改它以满足您的需要):

NoaggModel
OracleModel
将通过定义类似的方法来实现上述接口:

func (ng *NoaggModel) FilterData(filter interface{}) {
    fmt.Printf("data: %#v, filter: %#v\n", ng, filter)
}
然后,将
反序列化数据
(和
statData
)更改为接口类型
模型
,而不是
接口{}
。由于只有两种类型,因此可以通过使用开关来避免使用反射:

...
var deserializedData Model

switch sourceName {
case "noagg":
    deserializedData = new(models.NoaggModel)
case "oracle":
    deserializedData = new(models.OracleModel)
}
...
// Marshal the values into deserializedData which now holds an instance of the desired type
...
deserializedData.FilterData("Replace this string with your filter")

而且无需导入
反射

如果你是新手,你不应该使用反射。没有人应该推荐它,尤其是不要推荐给学习这门语言的人。我不知道你们的代码试图做什么。我试图调用我的自定义接口的函数。我称之为成功。并找到了如何传递参数,但得到了错误
reflect:Call,使用*models.NoaggModel作为类型models.NoaggModel
。我将更新我的问题,了解详细信息
Elem()
帮助取消reflect.Values中的指针引用,这可能会有所帮助。也不了解您试图做的事情,但我高度怀疑是否需要反射。接口应该做到这一点。我正在尝试在一些结构类型之间切换,并根据传入的字符串参数从正确的接口调用方法。我有一些用于数据源的接口,这些数据必须以不同的方式进行过滤和计数。所以我需要获取缓存,将其放入结构,并从不同的接口调用相同的方法。我描述了在调用缓存之前进行类型断言,因此我创建了一个
interface{}
类型的变量,将类型断言为所需的类型,获取缓存并尝试使用反射调用方法。我将方法的名称命名为字符串。这看起来非常漂亮和清晰。说到种类的数量,现在只有两种。在使用的几个月内,用量将不断增加。该应用程序将采用其他数据源,这类数据的列表将不断增加。同时,我确信列表不会超过30-40。但是,如果我重写代码,为了避免使用反射,我如何通过字符串名调用接口的方法,该字符串名作为参数来自
POST
。过滤数据后的每种类型(
oracleModel
NoaggModel
)都必须以不同的方式计数。所以我计划为每个接口创建方法,并按名称调用它们。如果不使用reflect,我需要对方法名进行切片或映射,并从映射中按名称调用它们?@Altenrion您还可以对
methodName
使用
开关
方法名{case“filterData”:反序列化数据。filterData(filter)}
。如果不是所有模型都实现所有方法?那么,您可以为每个方法创建一个接口,并尝试创建一个接口来检查模型类型是否实现了特定的方法。例如:OracleModel(countByX,countByY),NoaggMoldel(countByZ,countByS),我想以集中的方式保存,以避免大量的切换,并有或多或少的安全代码,以避免运行时errors@Altenrion试图理解的另一个尝试:)不使用不同的方法怎么样
OracleModel.Count(ax,by)
NoaggModel.Count(az,bs)
,但是您可以使用方法
Count(a接口{},b接口{})结果的接口
。然后,每个模型的计数方法将处理
a
b
的断言,以键入
X
/
Y
Z
/
s