Sök…
Anmärkningar
En annan fördel med att använda avstängda uttryckssträngar är att bytekompilatorn vanligtvis kan generera mer effektiv kod (5 - 10x snabbare) från dem.
Problemen med obegränsade uttryck
Det är en bra praxis att tillhandahålla uttryckssträngargument som avstängda strängar. Rubriken "Dubbel substitution" beskriver viktiga skäl bakom samma.
Kommandot expr utvärderar en operatörsbaserad uttryckssträng för att beräkna ett värde. Den här strängen är konstruerad av argumenten i åkallandet.
expr 1 + 2 ; # three arguments
expr "1 + 2" ; # one argument
expr {1 + 2} ; # one argument
Dessa tre invokationer är likvärdiga och uttryckssträngen är densamma.
Kommandona if , for och while använder samma utvärderingskod för sina villkorargument:
if {$x > 0} ...
for ... {$x > 0} ... ...
while {$x > 0} ...
Den största skillnaden är att villkorsuttryckssträngen alltid måste vara ett enda argument.
Som med alla argument i en kommandokallokation i Tcl, kan innehållet eventuellt underkastas substitution, beroende på hur de citeras / undkom:
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}
Det finns en skillnad i det tredje och det fjärde fallet eftersom backslissarna / hängslen förhindrar substitution. Resultatet är fortfarande detsamma, eftersom utvärderaren inuti expr själv kan utföra Tcl-variabel substitution och omvandla strängen till {1 + 2} .
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!
Här får vi problem med det avstängda argumentet: när utvärderaren i expr utför substitutioner har uttryckssträngen redan tolkats i operatörer och operander, så det som utvärderaren ser är en sträng som består av två operander utan operatör mellan dem. (Felmeddelandet " missing operator at _@_ in expression "$a _@_$b" ".)
I detta fall förhindrade variabel substitution före expr ett fel. Avstängning av argumentet förhindrade variabel substitution tills uttryck utvärdering, vilket orsakade ett fel.
Situationer som detta kan uppstå, oftast när ett uttryck att utvärdera skickas in som en variabel eller parameter. I dessa fall finns det inget annat val än att lämna argumentet oåtkomligt för att låta argumentutvärderaren "packa upp" uttryckssträngen för leverans till expr .
I de flesta andra fall gör det dock ingen skada att avstänga uttrycket och kan förhindra många problem. Några exempel på detta:
Dubbel substitution
set a {[exec make computer go boom]}
expr $a ; # expression string is {[exec make computer go boom]}
expr {$a} ; # expression string is {$a}
Den obegränsade formen kommer att utföra kommandosubstitutionen, som är ett kommando som förstör datorn på något sätt (eller krypterar eller formaterar hårddisken, eller vad har du). Den avstängda formen kommer att utföra en variabel substitution och sedan försöka (och misslyckas) att göra något av strängen "[exec make computer go boom]". Katastrof undviks.
Oändliga öglor
set i 10
while "$i > 0" {puts [incr i -1]}
Detta problem påverkar både for och while . Även om det verkar som att denna slinga skulle räkna ner till 0 och avsluta, är villkorargumentet till medan faktiskt alltid 10>0 eftersom det var vad argumentet utvärderades för att vara när kommandot while aktiverades. När argumentet stagade, det skickas till while kommandot som $i>0 och variabeln kommer att ersättas en gång för varje iteration. Använd det här istället:
while {$i > 0} {puts [incr i -1]}
Total utvärdering
set a 1
if "$a == 0 && [incr a]" {puts abc}
Vad är värdet på a efter att ha kört den här koden? Eftersom && operatören bara utvärderar den högra operanden om den vänstra operanden är sant, bör värdet fortfarande vara 1. Men faktiskt är det 2. Detta beror på att argumentutvärderaren redan har utfört alla variabla och kommandosubstitutioner när uttryckssträngen är utvärderas. Använd det här istället:
if {$a == 0 && [incr a]} {puts abc}
Flera operatörer (de logiska anslutningarna || och && , och den villkorade operatören ?: || && definierade för att inte utvärdera alla sina operander, men de kan bara fungera som utformade om uttryckssträngen har spårats.
Multiplicera en variabel med 17
set myVariable [expr { $myVariable * 17 }]
Detta visar hur du kan använda ett enkelt uttryck för att uppdatera en variabel. Kommandot expr uppdaterar inte variabeln för dig; du måste ta resultatet och skriva det till variabeln med set .
Observera att newlines inte är viktiga i det lilla språket som expr , och att lägga till dem kan göra längre uttryck mycket lättare att läsa.
set myVariable [expr {
$myVariable * 17
}]
Detta gör dock exakt samma sak.
Ringa ett Tcl-kommando från ett uttryck
Ibland måste du ringa ett Tcl-kommando från ditt uttryck. Antar att du till exempel behöver längden på en sträng i den. För att göra det använder du bara en [...] sekvens i uttrycket:
set halfTheStringLength [expr { [string length $theString] / 2 }]
Du kan ringa alla Tcl-kommandon på detta sätt, men om du befinner dig ringa expr själv, sluta! och tänk på om du verkligen behöver det extra samtalet. Du kan vanligtvis göra det bra genom att sätta det inre uttrycket i parentes.
Ogiltigt bareword-fel
I Tcl själv behöver inte en sträng som består av ett enda ord citeras. På uttryckssträngarnas språk som expr utvärderar måste alla operander ha en identifierbar typ.
Numeriska operander skrivs utan dekoration:
expr {455682 / 1.96e4}
Så är booleska konstanter:
expr {true && !false}
Tcl-variabelsubstitutionssyntax identifieras: operandens inställning till variabelns värde:
expr {2 * $alpha}
Detsamma gäller för kommandosubstitution:
expr {[llength $alpha] > 0}
Operander kan också vara matematiska funktionssamtal, med en kommaseparerad lista över operander inom parentes:
expr {sin($alpha)}
En operand kan vara en dubbelciterad eller spårad sträng. En dubbelciterad sträng kommer att ersättas precis som i en kommandorad.
expr {"abc" < {def}}
Om en operand inte är något av ovanstående är det olagligt. Eftersom det inte finns någon antydan om att visar vilken typ av ett ord är det, expr signaler en bareword fel.