Frage

Arbeiten mit TCL und ich möchte so etwas wie das Strategy-Muster implementieren. Ich möchte in der „Strategie“ in einer TCL-Funktion Druckausgabe passieren, so kann ich zwischen dem Druck auf den Bildschirm und das Drucken in eine Protokolldatei einfach wechseln. Was ist der beste Weg, dies in TCL zu tun?

War es hilfreich?

Lösung

TCL können Sie den Namen eines Verfahrens zum Speichern in einer Variablen und dann die Prozedur aufrufen diese Variable verwendet wird; so

proc A { x } {
   puts $x
}

set strat A
$strat Hello

die proc A anrufen und Hallo drucken

Andere Tipps

Neben der Antwort zeigt, wie Sie eine Prozedur einer Variablen zuweisen, können Sie auch den Namen einer Prozedur als Argument an eine andere Prozedur übergeben. Hier ist ein einfaches Beispiel:


proc foo { a } {
   puts "a = $a"
}

proc bar { b } {
   puts "b = $b"
}

proc foobar { c } {
   $c 1
}

foobar foo
foobar bar

Dies druckt a = 1 und b = 1

Ein etwas erweitert Beispiel dafür, was darüber aufgeführt war vielleicht die Strategie Muster deutlicher darzustellen:

proc PrintToPDF {document} {
<snip logic>
}

proc PrintToScreen {document} {
<snip logic>
}

proc PrintToPrinter {document} {
<snip logic>
}


set document "my cool formatted document here"

set printMethod "printer"


switch -- $printMethod {
    "printer" {
        set pMethodName "PrintToPrinter"
    }
    "pdf" {
        set pMethodName "PrintToScreen"
    }
    "screen" {
        set pMethodName "PrintToPDF"
    }
}

$pMethodName $document

Neben einem proc verwenden, die Sie tatsächlich einen Codeblock stattdessen verwenden könnte. Es gibt ein paar Variationen zu diesem Thema. erste ist die offensichtlichste, nur um es evaling.

set strategy {
    puts $x
}

set x "Hello"
eval $strategy
unset x

Das funktioniert, aber es gibt ein paar Nachteile. Zunächst wird die Hand, beide Teile des Codes müssen eine gemeinsame Namensgebung zu verwenden für die Argumente konspirieren. Dies ersetzt eine Namespace Kopfschmerzen (Procs) mit einem anderen (Einheimischer), und dies ist wohl tatsächlich schlechter .

Weniger offensichtlich ist, dass eval ihr Argument absichtlich ohne Kompilierung Bytecode interpretiert. Dies liegt daran, es wird angenommen, dass eval mit dynamisch generierte genannt wird, in der Regel eindeutige Argumente und ineffizient wäre Bytecode kompiliert, wenn der Bytecode nur einmal verwendet werden würde, in Bezug auf nur den Block unmittelbar zu interpretieren. Dies ist leichter zu beheben, so dass hier das Idiom:

set x "Hello"
if 1 $strategy
unset x

if, im Gegensatz zu eval, nicht kompiliert und cachen seinen Code-Block. Wenn der $strategy Block immer nur eine oder nur eine Handvoll von verschiedenen möglichen Werten ist, dann funktioniert dies sehr gut.

Dies hilft nicht bei allen mit dem yuckiness von Argumenten auf den Block mit lokalen Variablen übergeben. Es gibt eine Menge Möglichkeiten, um das, wie zu tun Ersetzungen in der gleichen Art und Weise tk tut Ersetzungen auf Befehl Argumente mit % ist. Sie können versuchen, einige Dinge zu tun hackish uplevel oder upvar zu verbrauchen. Zum Beispiel könnten Sie dies tun:

set strategy {
    puts %x
}

if 1 [string map [list %% % %x Hello] $strategy]

Auf den unwahrscheinlichen Fall, dass die Argumente ändern sich nicht sehr viel übergeben wird, funktioniert dies auch in Bezug auf die Bytecode-Kompilierung. Wenn auf der anderen Seite ändert sich das Argument oft, sollten Sie eval statt if 1 verwenden. Das ist nicht viel besser jedenfalls in Bezug auf die Argumente. Es gibt weniger Wahrscheinlichkeit der Verwirrung über das, was passiert ist und was nicht, weil Sie eine spezielle Syntax verwenden. Auch dies ist hilfreich, wenn Sie die Variablensubstitution verwenden möchten, bevor Sie einen Code-Block zurückkehrt: wie in set strategy "$localvar %x".

Zum Glück, tcl 8.5 hat wahre anonyme Funktionen , mit dem apply Befehl. Das erste Wort auf die Anwendung Befehl würde eine Liste der Argumente und Körper, als ob diese Argumente zu proc war aus angehoben worden. Die übrigen Argumente werden sofort als Argument für den anonymen Befehl übergeben.

set strategy [list {x} {
    puts $x
}]

apply $strategy "Hello"

Wie wäre es variable Funktionen? Ich erinnere mich nicht viel TCL (es ist schon eine Weile ...), aber vielleicht einer von ihnen tun würde, was Sie brauchen:

  • [$ var param1 param2]
  • [$ var] param1 param2
  • $ var param1 param2

Wenn ich falsch bin, jemand ist frei, mich zu korrigieren.

% set val 4444
4444

% set pointer val
val

% eval puts $$pointer
4444

% puts [ set $pointer ]
4444

% set tmp [ set $pointer ]
4444

Um zu klären, warum Jackson Methode funktioniert, denken Sie daran, dass in TCL, alles ist eine Zeichenfolge. Egal, ob Sie mit einer Zeichenkette, eine Funktion, eine Variable arbeiten, oder was auch immer es sein mag, alles ist eine Zeichenfolge. Sie können einen „Funktionszeiger“ Pass genau wie Sie eine „Datenzeiger“ kann. Einfach den Namen des Objekts verwenden, ohne führende „$“

Alles was oben erwähnt, obwohl, wenn sie von Namespace Namensraum bewegt, kann man als eine vorübergehende [namespace current ]::proc_name verwenden möchten, um sicherzustellen, dass Sie keine Pausen bekommt.
Für OO-Methoden, müssen Sie folgen was in diesem Thread ist: Übergeben geben~~POS=HEADCOMP wird ein Verfahren eines bestimmten Objekts als Eingangsargument in Tcl
Godspeed.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top