web-dev-qa-db-ja.com

TCLのifステートメント

次のコードのtclのifステートメントについて質問があります。

if {(($number == 1)&&($name == "hello")) || (($number == 0)&&($name == "yes"))} {
    #do something here
}

上記のコードは機能しますが、次のように書き留めておくと、

if {{$number == 1 && $name == "hello"} || {$number == 0&&$name == "yes"}} {
    #do something here
}

$numberはブール値であることが期待されていますが、なぜですか? 2番目の式は有効な式ではありませんか?それを修正するには?

14
user707549

中括弧_{}_と括弧_()_はnot Tclで交換可能です。

正式には、中括弧は( 1つの例外 を使用して)内容の置換をこれ以上実行しないことを示す一種の引用です。上記の最初のケースでは、これはその引数が置換なしでifに渡され、式として評価されることを意味します。式のサブ言語には、一般的なTclに対して非常に類似したブレース解釈スキームがあります。それらはリテラル値を示し、それに対して実行する追加の置換はありません。

対照的に、Tclでは括弧はほとんど特別ではありません。例外は、配列の要素の名前(たとえば、$foo(bar))、式のサブ言語(プログラミング全体の数式のようにグループ化に使用)、および正規表現のサブ言語(ここで、異なるタイプのグループ化といくつかの他のものです)。 Tclのコマンド名の一部として括弧を使用することは完全に合法です。ただし、バランスが取れていてもそうでなくてもかまいませんが、混乱を招くコードを書くことについてプログラマーが文句を言うかもしれません。

詳細

この特定のケースでは、このifのテスト式:

_if {{$number == 1 && $name == "hello"} || {$number == 0&&$name == "yes"}} {...}
_

に解析されます:

blah#1 LOGICAL_OR blah#2

ここで、各blahはリテラルです。残念ながら、_blah#1_(これは_$number == 1 && $name == "hello"_とまったく同じ)にはブール解釈がありません。 (また、_blah#2_も行いませんが、それを気にすることはありません。)ここでは間違いなく非常に問題が発生しています。

最も簡単な修正は、これらの偽の括弧を括弧に戻すことです:

_if {($number == 1 && $name == "hello") || ($number == 0&&$name == "yes")} {...}
_

きっとあなたが最初に欲しかったものだと思います。

警告:高度なトピック

ただし、他の修正は少し余分に追加することです:

_if {[expr {$number == 1 && $name == "hello"}] || [expr {$number == 0&&$name == "yes"}]} {...}
_

これは通常は良い考えではありません—余分な利益のために余分な大きさ—ですが、動的に生成された式をテスト条件として使用しようとしている場合には理にかなっています。 これを行わないこれを行う必要があると本当に確信している場合を除きます!私はそれを意味します。これは、ほとんど必要のない非常に高度な手法であり、多くの場合、全体的な目標を達成するためのより良い方法があります。 可能性必要だと思われる場合は、こちらのSOで質問してください。私たちはより良い方法を見つけようとします。ほとんどの場合、利用可能な方法があります。

33
Donal Fellows

つまり、ifは、条件スクリプトに特別な「ミニ言語」を使用します— exprコマンド で理解されるのと同じです。これは ifマニュアルページ に記載されています:

Ifコマンドはexpr1を式として評価します(exprが引数を評価するのと同じ方法で)。

LISPやUnixシェルに非常に似ているTcl自体とは対照的に、「exprミニ言語」は、Cのように感じられるという意味で、「より伝統的」です。

1
kostix

あなたが受け取っているエラーメッセージはそれを意味しているとは思いません$numberはブール値である必要があります(メッセージexpected boolean value but got "$number == 1 && $name == "hello"")。これは、文字列$number == 1 && $name == "hello"はブール値ではありません-確かにそうです。 if式で中括弧を使用する場合、これらの文字列は評価されず、単に文字列として解釈されます。

1
bmk

($number == 1)では、番号に1が割り当てられ、比較が行われます。例:1==1ここでの出力はブール値です。ただし、{$number == 1 && $name == "hello"}では、花の括弧$number1と比較されるため、$ numberは割り当てられないため、取得される出力はブール値ではありません。

1
fahad