Question

Travailler avec TCL et j'aimerais implémenter quelque chose comme le modèle de stratégie . Je souhaite passer à la "stratégie". pour imprimer une sortie dans une fonction TCL, afin que je puisse facilement basculer entre l’impression à l’écran et l’impression dans un fichier journal. Quelle est la meilleure façon de faire cela en TCL?

Était-ce utile?

La solution

TCL vous permet de stocker le nom d'une procédure dans une variable, puis d'appeler la procédure à l'aide de cette variable. alors

proc A { x } {
   puts $x
}

set strat A
$strat Hello

appellera le proc A et imprimera Bonjour

Autres conseils

Outre la réponse indiquant comment affecter une procédure à une variable, vous pouvez également transmettre le nom d'une procédure en tant qu'argument à une autre procédure. Voici un exemple simple:


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

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

proc foobar { c } {
   $c 1
}

foobar foo
foobar bar

Ceci imprimera a = 1 et b = 1

Un exemple légèrement élargi de ce qui a été énuméré ci-dessus pourrait illustrer plus clairement le modèle de stratégie:

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

Hormis l’utilisation d’un proc, vous pouvez également utiliser un bloc de code. Il y a quelques variations à ce sujet. La première est la plus évidente, il suffit de eval l’introduire.

set strategy {
    puts $x
}

set x "Hello"
eval $strategy
unset x

Cela fonctionne, mais il y a quelques inconvénients. Tout d’abord, les deux éléments de code doivent concorder avec l’utilisation d’une dénomination commune pour les arguments. Cela remplace un mal de tête d'espace de noms (procs) par un autre (locaux), ce qui est sans doute en réalité pire .

Ce qui est moins évident, c’est que eval interprète délibérément son argument sans avoir à compiler le bytecode. En effet, eval est supposé appelé avec des arguments générés de manière dynamique, généralement uniques, et la compilation en code-octet serait inefficace si le code-octet ne devait être utilisé qu'une seule fois, par rapport à une interprétation immédiate du bloc. C'est plus facile à résoudre, alors voici l'idiome:

set x "Hello"
if 1 $strategy
unset x

si , contrairement à eval , compile et met en cache son bloc de code. Si le bloc $ strategy ne contient qu'une ou plusieurs poignées possibles, cela fonctionne très bien.

Cela n’aide en rien le fait de passer des arguments au bloc avec des variables locales. Il y a plusieurs façons de contourner ce problème, par exemple, substitutions de la même manière que tk effectue des substitutions sur les arguments de commande avec les balises % . Vous pouvez essayer de faire des choses détournées avec niveau supérieur ou code supérieur . Par exemple, vous pouvez faire ceci:

set strategy {
    puts %x
}

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

Si les arguments transmis ne changent pas beaucoup, cela fonctionne bien en termes de compilation de code-octet. Par contre, si l'argument change souvent, vous devez utiliser eval au lieu de si 1 . Ce n'est pas beaucoup mieux de toute façon, en termes d'arguments. Il y a moins de risque de confusion entre ce qui est passé et ce qui ne l'est pas, car vous utilisez une syntaxe spéciale. Cela est également utile si vous souhaitez utiliser la substitution de variable avant de renvoyer un bloc de code: comme dans définir la stratégie "$ localvar% x" .

Heureusement, tcl 8.5 a de véritables fonctions anonymes , en utilisant la commande apply . Le premier mot de la commande apply serait une liste des arguments et leur corps, comme si ces arguments de proc avaient été extraits. Les arguments restants sont immédiatement transmis à la commande anonyme.

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

apply $strategy "Hello"

Pourquoi ne pas utiliser des fonctions variables? Je ne me souviens pas beaucoup de TCL (ça fait un moment ...), mais peut-être que l'un d'eux ferait ce dont vous avez besoin:

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

Si je me trompe, n'importe qui est libre de me corriger.

% set val 4444
4444

% set pointer val
val

% eval puts $pointer
4444

% puts [ set $pointer ]
4444

% set tmp [ set $pointer ]
4444

Pour préciser pourquoi la méthode de Jackson fonctionne, rappelez-vous que dans TCL, tout est une chaîne. Que vous travailliez avec une chaîne littérale, une fonction, une variable ou quoi que ce soit d'autre, tout est une chaîne. Vous pouvez passer un " fonction pointeur " tout comme vous pouvez utiliser un "pointeur de données": utilisez simplement le nom de l’objet sans précéder le signe "$".

Tout ce qui a été dit ci-dessus, bien que lors du déplacement d'un espace de noms vers un espace de noms, vous souhaitiez peut-être utiliser comme [espace de noms actuel] :: nom_proc , afin de vous assurer que vous n'obtiendrez aucune coupure.
Pour les méthodes OO, vous devez suivre le contenu de ce fil: Passer une méthode d'un objet spécifique comme argument d'entrée dans Tcl
Bon Dieu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top