2016-02-16 4 views
-1

Я столкнулся с проблемами использования библиотеки отражений. Я descided использовать его из-за многих Рекомендации, но я только учусь идти и некоторые части не очень легко ..Перейти: задуматься: вызвать слишком мало аргументов ввода

Я получил эту часть кода:

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 with too few input arguments. Но если я изменю reflect.ValueOf(statData) на reflect.ValueOf(&statData) чем ошибки reflect: call of reflect.Value.Call on zero Value

statData поставляется с одним из 2-х типов, и передняя этого типов У меня есть и методы структур, как это:

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

это Println также не работает. Паника кода выше, и метод не запускался. Где моя ошибка здесь?

Upd 1:

Найдено, что если удалить из параметров data в functioin, что я хочу позвонить, чем это требует красиво. Но! У меня есть statData как 1 строка, структур, поэтому тип NoaggModel. И в методе FilterData я получаю эту 1 строку как ng. Но мне нужно изменить его на []NoaggModel. Как вызвать reflect в этом случае и как передать параметр функции фильтра?

Upd 2: Я изменил несколько частей:

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

здесь, как передать правильный тип для filter, если он установлен в Ревеле контроллера и метод в модели. Или я должен установить тип в каждой модели и вызвать его в контроллере?

И в контроллере я писал:

//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 в коде выше, как это:

... 
    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 
+3

Если вы новичок в Go, вы не должны использовать отражение. Никто не должен рекомендовать его, особенно не кому-то, изучающему язык. Я понятия не имею, что ваш код пытается сделать. – Volker

+0

Я пытаюсь вызвать функцию моего пользовательского интерфейса. Я назову это успешно. И узнал, как передать параметры, но получает ошибку '' 'reflect: Call using * models.NoaggModel как типы models.NoaggModel'''. Я обновлю свои вопросы для деталей. – Altenrion

+0

'Elem()' помогает указателям разыменования внутри reflect.Values ​​и может помочь. – Volker

ответ

1

Отражение не просто. И следует избегать, если это возможно.

Я признаю, что я рекомендовал использовать reflect для динамического создания экземпляров типов на основе карты, что очень полезно, если вы не знаете, какие типы вам придется обрабатывать. Но в вашем случае вы должны рассмотреть возможность использования интерфейсов.

Пока я не знаю, что вы хотите достичь, я хотел бы предложить, начиная от создания интерфейса, что все модели должны реализовать (изменить его в соответствии с вашими потребностями):

type Model interface { 
    FilterData(interface{}) 
} 

NoaggModel и OracleModel затем осуществить вышеупомянутый интерфейс, определив подобные методы, как это:

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

затем изменить deserializedDatastatData), чтобы иметь тип интерфейса Model в вместо interface{}. А поскольку у вас есть только два типа, вы можете избежать использования отражения при наличии переключателя вместо:

... 
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!

+0

Это выглядит очень красиво и ясно. Говоря о количестве типов, есть только 2 сейчас. Эта сумма будет расти в течение месяцев использования. в приложение будут включены другие источники данных, и список этих типов будет расти. В то же время, я уверен, что список будет не больше 30-40. – Altenrion

+0

Тем не менее, если бы я переписал код, чтобы избежать использования рефлекса, как я могу вызвать методы интерфейса по имени строки, это приходит как параметр из '' 'POST'''. Каждый тип ('' 'oracleModel'',' 'NoaggModel'') после фильтрации данных должен учитываться по-разному. Поэтому я планировал создавать методы для каждого интерфейса и называть их по имени. Если не использовать рефлексию, мне нужно будет сделать фрагмент или карту имен методов и вызвать их по имени из карты? – Altenrion

+1

@Altenrion Вы также можете использовать 'switch' для' methodName': 'switch methodName {case" filterData ": deserializedData.FilterData (filter) ...}'. И если не все модели реализуют все методы? Ну, тогда вы можете создать интерфейс для каждого из методов и попытаться сделать ['type assertion'] (https://golang.org/ref/spec#Type_assertions), чтобы проверить, реализует ли тип модели определенный метод. – ANisus

Смежные вопросы