2014-03-25 10 views
5

Ich versuche, einen Dispatcher von Funktionen in Rebol 3 zu erstellen, so dass für jede Zeichenfolge, die das Programm empfängt, ist eine zugeordnete Funktion aufgerufen werden.So rufen Sie eine Funktion aus einer Reihe von Funktionen und rufen Sie

Zum Beispiel:

handlers: make map! [ 
    "foo" foo-func 
    "bar" bar-func 
] 

wo foo-func und bar-func sind Funktionen:

foo-func: func [ a b ] [ print "foo" ] 
bar-func: func [ a b ] [ print "bar" ] 

Die Idee ist, select die Funktion aus der Zeichenfolge beginnen, so:

f: select handlers "foo" 

so dass die Ausführung f ist die gleiche wie foo-func Ausführung und ruft dann f mit einigen Argumenten:

f param1 param2 

Ich habe versucht, die Worte in den map! zitieren, oder mit get-Worten, aber ohne Erfolg.

ein get-word! an der Konsole verwenden, ohne map! Durch es funktioniert:

>> a: func [] [ print "Hello world!" ] 
>> a 
Hello world! 
>> b: :a 
>> b 
Hello world! 

Jede Hilfe sehr geschätzt.

+0

, das eine Arbeit auch foo: func [] [print "Hallo"] in System/Kontexten/Anwender erhalten Sie auf Wort "foo" – endo64

Antwort

4

Es b ist Eter, um tatsächlich den Verweis auf die Funktion in der Map zu haben, anstatt ein Wort, das sich auf die Funktion bezieht.Wenn Sie ein Wort speichern, dann müssen Sie das Wort stellen Sie sicher, wird an ein Objekt gebunden, die einen Verweis auf diese Funktion hat, wie folgt aus:

handlers: object [ 
    foo-func: func [ a b ] [ print "foo" ] 
    bar-func: func [ a b ] [ print "bar" ] 
] 

handler-names: map [ 
    "foo" foo-func 
    "bar" bar-func 
] 

apply get in handlers select handler-names name args 

Aber wenn Sie nur einen Verweis auf die Funktion in Ihrer Karte haben, Sie müssen nicht das doppelte indirekt tun, und Ihr Code sieht so aus:

Cleaner-Code, und effizienter zu. Oder wenn Sie vorsichtig genug, wie folgt aus:

handlers/(name) a b 

Der Pfad Verfahren oben wird auch funktionieren, wenn Sie den Code wollen, nichts tun, wenn es keine Handler ist - häufig in Fällen, in denen Sie optional Handler haben, wie in GUIs.

Sie können sogar mehr als einen Verweis auf dieselbe Funktion mit unterschiedlichen Schlüsselnamen haben. Sie müssen den Wörtern keine Funktionen zuweisen, sie sind nur Werte. Sie können auch die Pfadmethode verwenden, um die Handler an erster Stelle zu sammeln und eine reduce zu speichern.

handlers: make map! 10 ; preallocate as many entries as you expect 
handlers/("foo"): func [ a b ] [ print "foo" ] 
handlers/("bar"): func [ a b ] [ print "bar" ] 
handlers/("baz"): select handlers "bar" ; multiple references 

Das Pfadsyntax ist nur eine andere Art und Weise poke zu nennen, aber einige bevorzugen es. Wir müssen die String-Werte wegen eines (hoffentlich temporären) Syntaxkonflikts in Parens setzen, aber innerhalb dieser Parens funktionieren die String-Keys. Es ist eine schnellere Alternative zu do select oder poke.

+0

Ein wenig mehr Detail als die Antwort von @sqlab, die den besten Ansatz hatte, aber nicht erwähnte, wie man die Funktionen aufruft, und die Nachteile des ursprünglichen Ansatzes nicht aufzeigte. – BrianH

+0

Sehr interessant die Pfadsyntax, die direkt die Zeichenfolgen als Schlüssel verwendet – kronwiz

2

Versuchen: .... f: Wählen Handler "foo" ....

+0

@ Antwort WayneTsui ist besser in der Leistung zu sein scheint. – giuliolunati

4

foo-func in Ihrer Karte ist nur ein unevaluierten Wort

>> type? select handlers "foo" 
== word! 

Sie sollten zuerst erstellen Sie Ihre Funktionen und reduzieren Sie dann den Block, verwenden Sie Ihre Handler Karte für die Erstellung von so

handlers: make map! reduce [ 
    "foo" :foo-func 
    "bar" :bar-func 
] 

dann haben Sie innerhalb von Funktionen Ihre Karte

>> type? select handlers "foo" 
== function! 
+0

Ich habe die ': foo-func'-Syntax verwendet, aber ich vermisste das' reduce' vollständig, um den Block auszuwerten. – kronwiz

5

select handlers "foo" nur das Wort foo-func erhalten:

f: select handlers "foo" 
probe f ;will get: foo-func 

Sie müssen ihren Inhalt zu erhalten:

f: get f 
f 1 2 ;will print "foo" 

Oder kompakte:

f: get select handlers "foo"