Suche…
Bemerkungen
Ein weiterer Vorteil der Verwendung von geschweiften Ausdruckszeichenfolgen besteht darin, dass der Byte-Compiler normalerweise effizienteren Code (5 - 10-fach schneller) aus ihnen generieren kann.
Die Probleme mit ungepflegten Ausdrücken
Es empfiehlt sich, Ausdrucksstringargumente als geschweifte Strings anzugeben. Die Überschrift "Doppelsubstitution" umreißt wichtige Gründe dafür.
Der Befehl expr wertet eine expr Ausdruckszeichenfolge aus, um einen Wert zu berechnen. Diese Zeichenfolge wird aus den Argumenten beim Aufruf erstellt.
expr 1 + 2 ; # three arguments
expr "1 + 2" ; # one argument
expr {1 + 2} ; # one argument
Diese drei Aufrufe sind gleichwertig und die Ausdruckszeichenfolge ist dieselbe.
Die Befehle if , for und while verwenden für ihre Bedingungsargumente denselben Auswertungscode:
if {$x > 0} ...
for ... {$x > 0} ... ...
while {$x > 0} ...
Der Hauptunterschied besteht darin, dass der Bedingungsausdruck immer ein einzelnes Argument enthalten muss.
Wie bei jedem Argument in einem Befehlsaufruf in Tcl kann der Inhalt einer Substitution unterzogen werden oder nicht, je nachdem, wie er in Anführungszeichen / Escape-Zeichen gesetzt wird:
set a 1
set b 2
expr $a + $b ; # expression string is {1 + 2}
expr "$a + $b" ; # expression string is {1 + 2}
expr \$a + \$b ; # expression string is {$a + $b}
expr {$a + $b} ; # expression string is {$a + $b}
Es gibt einen Unterschied im dritten und vierten Fall, da die Backslashes / Klammern eine Substitution verhindern. Das Ergebnis ist immer noch dasselbe, da der Evaluator in expr selbst die Tcl-Variablensubstitution durchführen und die Zeichenfolge in {1 + 2} expr kann.
set a 1
set b "+ 2"
expr $a $b ; # expression string is {1 + 2}
expr "$a $b" ; # expression string is {1 + 2}
expr {$a $b} ; # expression string is {$a $b}: FAIL!
Hier geraten wir mit dem geschweiften Argument in Schwierigkeiten: Wenn der Evaluator in expr Substitutionen ausführt, wurde die Ausdruckszeichenfolge bereits in Operatoren und Operanden analysiert. Der Evaluator sieht also einen String, der aus zwei Operanden ohne Operator besteht. (Die Fehlermeldung lautet " missing operator at _@_ in expression "$a _@_$b" ".)
In diesem Fall verhinderte die Variablensubstitution vor dem expr einen Fehler. Durch das Abstützen des Arguments wurde die Variablensubstitution bis zur Auswertung des Ausdrucks verhindert, was zu einem Fehler führte.
Situationen wie diese können vorkommen, meistens, wenn ein auszuwertender Ausdruck als Variable oder Parameter übergeben wird. In diesen Fällen bleibt nichts anderes übrig, als das Argument nicht versteift zu lassen, damit der Argumentbewerter die Ausdruckszeichenfolge für die Übergabe an expr "entpacken" expr .
In den meisten anderen Fällen schadet das Abspannen des Ausdrucks jedoch nicht und kann viele Probleme vermeiden. Einige Beispiele dafür:
Doppelte Substitution
set a {[exec make computer go boom]}
expr $a ; # expression string is {[exec make computer go boom]}
expr {$a} ; # expression string is {$a}
Das nicht versteifte Formular führt die Befehlssubstitution aus. Hierbei handelt es sich um einen Befehl, der den Computer irgendwie zerstört (oder die Festplatte verschlüsselt oder formatiert oder was Sie haben). Das geschweifte Formular führt eine Variablensubstitution aus und versucht dann (und schlägt fehl), etwas aus der Zeichenfolge "[exec make computer go boom]" zu machen. Katastrophe abgewendet.
Endlose Schleifen
set i 10
while "$i > 0" {puts [incr i -1]}
Dieses Problem betrifft sowohl for als auch while . Während es scheint, dass diese Schleife auf 0 heruntergezählt und beendet wird, ist das Bedingungsargument to while eigentlich immer 10>0 da dies das Argument war, als der while Befehl aktiviert wurde. Wenn das Argument geklammert ist, wird es an den while Befehl als $i>0 , und die Variable wird für jede Iteration einmal ersetzt. Verwenden Sie stattdessen diese:
while {$i > 0} {puts [incr i -1]}
Gesamtbewertung
set a 1
if "$a == 0 && [incr a]" {puts abc}
Was ist der Wert von a nachdem dieser Code ausgeführt wurde? Da der Operator && nur den rechten Operanden auswertet, wenn der linke Operand true ist, sollte der Wert immer noch 1 sein. Tatsächlich sind es 2. Dies ist darauf zurückzuführen, dass der Argument-Evaluator alle Variablen- und Befehlssubstitutionen bereits ausgeführt hat, wenn die Ausdruckszeichenfolge vorliegt bewertet. Verwenden Sie stattdessen diese:
if {$a == 0 && [incr a]} {puts abc}
Mehrere Operatoren (die logischen Verknüpfungen || und && und der Bedingungsoperator ?: :) Sind so definiert, dass nicht alle Operanden ausgewertet werden. Sie können jedoch nur wie vorgesehen arbeiten, wenn die Ausdruckszeichenfolge festgelegt ist.
Eine Variable mit 17 multiplizieren
set myVariable [expr { $myVariable * 17 }]
Dies zeigt, wie Sie einen einfachen Ausdruck zum Aktualisieren einer Variablen verwenden können. Der Befehl expr aktualisiert die Variable nicht für Sie. Sie müssen das Ergebnis nehmen und mit set in die Variable schreiben.
Beachten Sie, dass Zeilenumbrüche in der kleinen Sprache, die von expr verstanden wird, nicht wichtig sind, und das Hinzufügen von expr das Lesen erheblich vereinfacht.
set myVariable [expr {
$myVariable * 17
}]
Das tut genau das gleiche.
Aufruf eines Tcl-Befehls aus einem Ausdruck
Manchmal müssen Sie einen Tcl-Befehl aus Ihrem Ausdruck aufrufen. Angenommen, Sie benötigen die Länge einer Zeichenfolge. Dazu verwenden Sie einfach eine [...] Sequenz im Ausdruck:
set halfTheStringLength [expr { [string length $theString] / 2 }]
Sie können jeden Tcl-Befehl auf diese Weise aufrufen, aber wenn Sie sich als expr selbst aufrufen, hören Sie auf! und überlegen Sie, ob Sie diesen zusätzlichen Anruf wirklich benötigen. Normalerweise können Sie dies auch gut tun, indem Sie den inneren Ausdruck in Klammern setzen.
Ungültiger Barewort-Fehler
In Tcl selbst muss eine aus einem einzelnen Wort bestehende Zeichenfolge nicht in Anführungszeichen gesetzt werden. In der Sprache der Ausdruckszeichenfolgen, die expr auswertet, müssen alle Operanden einen identifizierbaren Typ haben.
Numerische Operanden werden ohne Verzierung geschrieben:
expr {455682 / 1.96e4}
So sind boolesche Konstanten:
expr {true && !false}
Die Syntax der Tcl-Variablenersetzung wird erkannt: Der Operand wird auf den Wert der Variablen gesetzt:
expr {2 * $alpha}
Dasselbe gilt für die Befehlsersetzung:
expr {[llength $alpha] > 0}
Operanden können auch mathematische Funktionsaufrufe mit einer durch Kommas getrennten Liste von Operanden in Klammern sein:
expr {sin($alpha)}
Ein Operand kann eine doppelte Anführungszeichenfolge sein. Eine Zeichenfolge mit doppelten Anführungszeichen wird wie in einer Befehlszeile ersetzt.
expr {"abc" < {def}}
Wenn ein Operand nicht zu den oben genannten gehört, ist er illegal. Da gibt es keinen Hinweis darauf ist , dass was für ein Wort zeigt es ist, expr signalisiert einen Bareword Fehler.