2016-03-26 3 views
1

Ich möchte eine Funktion basierend auf einer Zeichenfolge angeben. Ich bekomme Strings aus einer Map, in dem Beispiel unten sind es die Werte in function während man mit der Map interagiert. Wenn nun beispielsweise der String-Wert function == "networkInfo" verwendet wird, möchte ich diesen Wert als Namen einer echten Funktion "behandeln". Es ist schwer zu erklären, aber ich denke ihr wisst was ich meine.Konvertieren Zeichenfolge Wert Funktionsaufruf

Mein Ziel ist es, die switch-Anweisung zu entfernen und c.AddFunc(spec, func() { networkInfo() }) direkt aufrufen wo NetworkInfo der Funktionsname ist, extrahiert aus Zeichenfolge function. Ich weiß, das ist möglich, aber ich weiß nicht, wie :(Hilfe geschätzt wird

// 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

Ich nehme an, alle Funktionen haben die gleiche Signatur? d. h. 'func()' –

+0

Funktionieren auch alle Funcs im gleichen Paket? –

+0

Ja, alle Funktionen (alle "Aufgaben") haben die gleiche Signatur. Und alle Funktionen leben im selben Paket. –

Antwort

3

Warum nicht so etwas wie:.!

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

Wenn Sie Variation benötigen Signaturen Ihres funcs Sie dann würde tatsächlich Reflexion benötigen, aber wenn die Typen der Funktionen alle gleich sind, dann könnte die Verwendung dieses Kartenansatzes eine einfachere Lösung ohne den Overhead der Reflexion sein.

Der einzige Weg, den ich gefunden habe, um Funktionen zu finden Name in einem Paket ist, indem die Quelldateien tatsächlich analysiert werdenist ein Beispiel zum Suchen von Funktionen und Speichern dieser in einer Karte mit dem Namen als Schlüssel.

Der Go-Linker wird unbeaufsichtigte Funcos unbeaufsichtigt löschen. Wenn Sie also nur durch Reflektion auf die Funktion verweisen, wird die Verbindung unterbrochen. Deshalb ist der Kartenansatz, den ich vorschlage, überlegen. Es lässt den Linker wissen, dass die Funktion verwendet wird.

+0

Danke für deine Antworten, sie helfen mir wirklich sehr. In Ihrem Vorschlag sehe ich eine 'taskDefs'-Karte [string] func(), wo alle" Aufgaben "definiert werden müssen. Ist es nicht möglich, diesen Teil zu überspringen? Auf diese Weise kann ich Aufgaben hinzufügen, indem ich einfach den Funktionsnamen in eine Konfigurationsdatei setze und die Funktion in mein Aufgabenpaket implementiere, ohne etwas zu "taskDefs" hinzufügen zu müssen. –

+1

@RogierLommers Ich verstehe, was Sie wollen; um die explizite Zuordnung zwischen Name und Funktion zu vermeiden. Es gibt zwei Probleme damit: 1) Ich sehe keine Möglichkeit, dies durch Reflektion zu tun, es sei denn, du liest die Quelle dynamisch mit dem Go-Parser zur Laufzeit, was viel schwerer von einem Ansatz erscheint, das gleiche letztendlich zu tun (map Name zu funktionieren). 2) Der Go-Linker löscht nicht referenzierte Funktionen, daher besteht das Risiko, dass die Funktion nicht einmal in der endgültigen Binärdatei enthalten ist, wenn sie nirgendwo anders referenziert wird, was bedeutet, dass sie nicht funktioniert. –