duanji5746 2016-02-16 09:53
浏览 75
已采纳

执行:反射:使用很少的输入参数进行调用

I've stucked with problems of using reflect library. I descided to use it because of many recomendations, but i'm just learning go and some parts are not really easy..

I've got this part of code :

 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
 }

If I execute the method like this, I get error : reflect: Call with too few input arguments. But if I change reflect.ValueOf(statData) on reflect.ValueOf(&statData) than error is reflect: call of reflect.Value.Call on zero Value

statData comes with one of 2 types, and fore this types I have structs and methods, like this :

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)
}

this Println also not works. Code panics above , and method was not triggered. Where is my mistake here?

Upd 1:

Found that if I remove param data in functioin that I want to call, than it calls nicely. But! I have statData as 1 row, of structs, so type is NoaggModel. And in the method FilterData I get this 1 row as ng. But I need to change it to the []NoaggModel. How to call reflect in this case and how to pass parameter to the filter function ?

Upd 2: I modified few parts :

func (ng *NoaggModel) FilterData(filter interface{}, data NoaggModel) {
    fmt.Println("data : ",ng)
}

In here, how to pass correct type to filter, if it is set up in revel controller, and method is in model. Or should I set the type in each model and call it in controller?

And in controller I wrote :

//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 is a row of type NoaggModel, but I get the error :

 reflect: Call using *models.NoaggModel as type models.NoaggModel 

The type was set also by reflect in code above, like this :

    ...
    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
  • 写回答

1条回答 默认 最新

  • duanqiao9541 2016-02-16 13:56
    关注

    Reflection is not easy. And should be avoided if possible.

    I admit that I did recommend using reflect to dynamically create instances of types based on a map, which is really useful when you don't know which types you might have to handle. But in your case you should consider using interfaces.

    While I don't really know what you want to achieve, I would suggest starting by creating an interface that all your Models need to implement (modify it to fit your needs):

    type Model interface {
        FilterData(interface{})
    }
    

    NoaggModel and OracleModel would then implement the above interface by defining similar methods like this:

    func (ng *NoaggModel) FilterData(filter interface{}) {
        fmt.Printf("data: %#v, filter: %#v
    ", ng, filter)
    }
    

    Then, change deserializedData (and statData) to be of the interface type Model instead of interface{}. And since you only have two types, you can avoid using reflect by having a switch instead:

    ...
    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")
    

    And it is done without having to import reflect!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助