2016-03-26 3 views
1

Я хочу указать функцию на основе строки. Я получаю строки из карты, в приведенном ниже примере это значения в function во время взаимодействия с картой. Например, когда значение строки function == «networkInfo», я хотел бы «обработать» это значение как имя реальных функций. Трудно объяснить, но я думаю, вы, ребята, поймете, что я имею в виду.Преобразование строкового значения в вызов функции

Моя цель - удалить оператор switch и напрямую вызвать c.AddFunc(spec, func() { networkInfo() }) где networkInfo - это имя функции, извлеченное из строки function. Я знаю, что это возможно, но я не знаю, как :(Помощь ценится

// ScheduleCronjobs starts the scheduler 
func ScheduleCronjobs() { 

tasks := props.P.GetStringMapString("tasks") 
log.Infof("number of tasks: %d", len(tasks)) 

if len(tasks) != 0 { 
    c := cron.New() 

    // for each task, initialize 
    for function, spec := range tasks { 
     switch function { 
     case "networkInfo": 
      c.AddFunc(spec, func() { networkInfo() }) 
     case "bla": 
      c.AddFunc(spec, func() { bla() }) 
     default: 
      log.Errorf("unknown task: %q", function) 
     } 
    } 
    c.Start() 
} 

// after initialization, send out confirmation message 
slack.SendMessage("tasks initialized", props.P.GetString("channel")) 
} 
+0

Я предполагаю, что все funcs имеют одинаковую подпись? то есть 'func()' –

+0

Кроме того, выполняются ли все функции в одном пакете? –

+0

Да, все функции (все «задачи») имеют одну и ту же подпись. И все функции живут в одном пакете. –

ответ

3

Почему не что-то вроде:.!

taskDefs := map[string]func(){ 
    "networkInfo": networkInfo, 
    "bla": bla, 
} 

for function, spec := range tasks { 
    if fn, ok := taskDefs[function]; ok { 
    c.AddFunc(spec, func() { fn() }) // not sure if you need the enclosing func 
    } else { 
    log.Errorf("unknown task: %q", function) 
    } 
} 

Если вам не нужно варьируя подписи ваших funcs, то вам 'd действительно нуждается в отражении, но если типы функций одинаковы, то использование этого подхода карты может быть более простым решением без накладных расходов.

Единственный способ найти функции по имя в пакете - это фактически разбор исходных файлов. This repo - пример поиска funcs и хранения их на карте с именем в качестве ключа.

Коммандер Go беззвучно удаляет неиспользуемые функции, поэтому, если единственный способ, которым вы ссылаетесь на функцию, - это отражение, которое оно сломает. Вот почему подход к карте, который я предлагаю, превосходит; это позволит компоновщику знать, что функция func используется.

+0

Спасибо за ваши ответы, они действительно мне очень помогают. В вашем предположении я вижу «taskDefs' map [string] func(), где должны быть определены все« задачи ». Невозможно пропустить эту часть? Таким образом, я могу добавить задачи, просто поместив имя функции в файл конфигурации и реализовать функцию в своем пакете задач, не добавляя что-то в 'taskDefs'. –

+1

@RogierLommers Я понимаю, чего вы хотите; чтобы избежать явного сопоставления между именем и функцией. Есть две проблемы с этим: 1) Я не вижу способа сделать это с помощью отражения, если вы не динамически читаете источник с парсером go во время выполнения, что кажется более тяжелым для подхода к тому же в конечном итоге (карта от имени к функции). 2) Компонент go упустит неотправленные функции, поэтому существует риск того, что функция не будет даже в финальном двоичном файле, если она не упоминается нигде, что означает, что она не будет работать. –

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