サーチ…
備考
ブレースされた式の文字列を使用するもう1つのメリットは、バイトコンパイラは通常、より効率的なコード(5〜10倍高速)を生成できることです。
言い換えられない式の問題
式の文字列引数は、ブレースされた文字列として提供することをお勧めします。 「二重置換」の見出しには、その背後にある重要な理由が記載されています。
exprコマンドは、演算子ベースの式文字列を評価して値を計算します。この文字列は、呼び出しの引数から構成されます。
expr 1 + 2 ; # three arguments
expr "1 + 2" ; # one argument
expr {1 + 2} ; # one argument
これらの3つの呼び出しは同等であり、式の文字列は同じです。
if 、 for 、およびwhileコマンドは、条件引数に同じ評価コードwhile使用します。
if {$x > 0} ...
for ... {$x > 0} ... ...
while {$x > 0} ...
主な違いは、条件式の文字列は常に単一の引数でなければならないということです。
Tclのコマンド呼び出しのすべての引数と同様に、内容は引用/脱出方法に応じて置換される場合とされない場合があります。
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}
バックスラッシュ/中括弧が置換を防ぐので、3番目と4番目のケースに違いがあります。 expr中の評価者自身がTcl変数置換を実行し、その文字列を{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!
exprのエバリュエータが代入を実行するとき、式の文字列はすでに演算子とオペランドに解析されているので、評価者は2つのオペランドの間に演算子を持たない文字列であると見なします。 (エラーメッセージはmissing operator at _@_ in expression "$a _@_$b" "のmissing operator at _@_ in expression "$a _@_$b"がありmissing operator at _@_ in expression "$a _@_$b" 。)
この場合、 exprが呼び出される前の変数の代入はエラーを防ぎます。引数の補足は、エラーを引き起こした式の評価まで変数の置換を防いだ。
このような状況が発生する可能性があります。最も一般的には、評価する式が変数またはパラメータとして渡されます。そのような場合、引数エバリュエーターがexprへの配送のために式文字列を "解凍"できるように引数を残しておく以外に選択肢はありません。
しかし、他のほとんどのケースでは、式を補うことは害ではなく、実際には多くの問題を回避することができます。これのいくつかの例:
二重置換
set a {[exec make computer go boom]}
expr $a ; # expression string is {[exec make computer go boom]}
expr {$a} ; # expression string is {$a}
unbraced形式は、コマンドの置換を実行します。これは、コンピュータを何らかの形で破壊するコマンドです(または、ハードディスクを暗号化またはフォーマットします)。補完されたフォームは、変数の置換を行い、文字列 "[exec make computer go boom]"を作成しようと試みます(そして失敗します)。災害は避けられた。
無限ループ
set i 10
while "$i > 0" {puts [incr i -1]}
この問題はforとwhile両方for影響whileます。このループは0にカウントダウンして終了するようですが、whileの条件引数は、 whileコマンドがアクティブになったときに引数が評価されたため、実際には常に10>0です。引数が補完されると、 $i>0としてwhileコマンドに渡され、変数は各反復ごとに1回置換されます。代わりにこれを使用してください:
while {$i > 0} {puts [incr i -1]}
総合評価
set a 1
if "$a == 0 && [incr a]" {puts abc}
このコードを実行しa後のaの値は何ですか? &&演算子は左のオペランドが真の場合にのみ右のオペランドを評価するので、値は1のままです。しかし実際は2です。これは、引数エバリュエーターが式の文字列が評価される。代わりにこれを使用してください:
if {$a == 0 && [incr a]} {puts abc}
いくつかの演算子(論理&& ||と&& 、および条件付き演算子?: && 、すべてのオペランドを評価しないように定義されていますが、式ストリングが補われている場合にのみ設計どおりに動作します。
変数に17を掛ける
set myVariable [expr { $myVariable * 17 }]
これは、簡単な式を使って変数を更新する方法を示しています。 exprコマンドは変数を更新しません。結果を受け取り、 set使って変数に書き込む必要があります。
exprで理解できる小さな言語では、改行は重要ではないことに注意してください。長い行を追加すると読みやすくなります。
set myVariable [expr {
$myVariable * 17
}]
しかしこれはまったく同じことです。
式からTclコマンドを呼び出す
場合によっては、式からTclコマンドを呼び出す必要があります。たとえば、文字列の長さが必要であるとします。これを行うには、次の式で[...]シーケンスを使用します。
set halfTheStringLength [expr { [string length $theString] / 2 }]
このようにしてTclコマンドを呼び出すことはできますが、自分自身がexpr呼び出している場合は停止してください。その余分な電話が本当に必要かどうかを考えてください。内側の式をカッコで囲むことで、通常はうまくやることができます。
無効なbarewordエラー
Tcl自体では、1つの単語からなる文字列を引用符で囲む必要はありません。 expr評価する式文字列の言語では、すべてのオペランドに識別可能な型が必要です。
数値オペランドはデコレーションなしで記述されます。
expr {455682 / 1.96e4}
ブール定数は以下のようになります。
expr {true && !false}
Tcl変数の置換構文が認識されます:オペランドは変数の値に設定されます:
expr {2 * $alpha}
同じことがコマンド置換にも適用されます:
expr {[llength $alpha] > 0}
オペランドは、カッコで囲まれたオペランドのカンマ区切りリストを使用して、数学的関数呼び出しでもあります。
expr {sin($alpha)}
オペランドは二重引用符または括弧で囲むことができます。二重引用符で囲まれた文字列は、コマンドラインのように置換されます。
expr {"abc" < {def}}
オペランドが上記のいずれかでない場合、それは違法です。 exprは、どんな種類の単語であるかを示すヒントがないので、barewordエラーを通知します。