web-dev-qa-db-fra.com

la déclaration if dans TCL

J'ai une question à propos de si déclaration dans tcl du code suivant:

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

Le code ci-dessus fonctionne, mais si je l’écrivais comme ceci:

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

Il se plaint que le $number est censé être un booléen, pourquoi? La seconde n'est-elle pas une expression valide? Comment le corriger?

11
user707549

Les accolades, {}, et les parenthèses, (), sont pas interchangeables dans Tcl.

Formellement, les accolades sont (avec ne exception ) une sorte de citation qui indique qu'aucune substitution supplémentaire ne doit être effectuée sur le contenu. Dans le premier cas ci-dessus, cela signifie que cet argument est remis à if sans substitution, qui l'évalue comme une expression. L'expression sous-langage a un schéma d'interprétation fortement analogue à Tcl général; ils désignent une valeur littérale sans autre substitution à effectuer.

En revanche, les parenthèses ne sont généralement pas spéciales dans Tcl. Les exceptions se trouvent dans les noms des éléments de tableaux (par exemple, $foo(bar)), dans le sous-langage de l'expression (qui les utilise pour le regroupement, comme dans les expressions mathématiques utilisées dans la programmation) et dans le sous-langage de l'expression régulière différent type de groupement et quelques autres choses). Il est tout à fait légal d'utiliser des parenthèses - équilibrées ou non - dans le nom d'une commande dans Tcl, mais vos collègues de programmation pourraient vous plaindre de toute façon pour avoir écrit du code déroutant.

Les particularités

Dans ce cas spécifique, l'expression test de cette if:

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

est analysé dans:

blah # 1 LOGICAL_OR blah # 2

où chaque blah est un littéral. Malheureusement, blah#1 (qui est exactement égal à $number == 1 && $name == "hello") n'a pas d'interprétation booléenne. (Ni blah#2 mais nous ne prenons jamais la peine de considérer cela.) Les choses vont vraiment très mal ici!

La solution la plus simple consiste à remplacer ces fausses accolades par des parenthèses:

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

Je parie que c'est ce que tu voulais à l'origine.

Avertissement: sujet avancé

Cependant, l’autre solution consiste à ajouter un petit plus:

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

Ce n’est normalement pas une bonne idée (encombrement excessif sans gain supplémentaire), mais il est logique que vous essayiez d’utiliser une expression générée dynamiquement comme condition de test. Ne faites pas cela à moins d'être vraiment certain de votre besoin faire cela! Je le pense vraiment. C'est une technique très avancée dont vous n'avez presque jamais besoin et il existe souvent une meilleure façon d'atteindre votre objectif général. Si vous pensez que pourriez en avoir besoin, posez des questions ici sur SO et nous essaierons de trouver une meilleure solution; il y en a presque toujours un disponible.

33
Donal Fellows

En bref: if utilise un "mini langage" spécial pour son script de condition, identique à celui compris par la commande expr . Ceci est indiqué dans la page de manuel if :

La commande if évalue expr1 en tant qu'expression (de la même manière que expr évalue son argument).

Contrairement à Tcl lui-même, qui ressemble assez à LISP et/ou à Unix Shell, ce "expr mini language" est beaucoup plus "traditionnel" dans le sens où il ressemble à C.

1
kostix

Je pense que le message d'erreur que vous obtenez ne signifie pas que $number doit être un booléen (j'ai reçu le message expected boolean value but got "$number == 1 && $name == "hello"") . Cela signifie que la chaîne $number == 1 && $name == "hello" n'est pas une valeur booléenne - ce qui est vraiment vrai . Si vous utilisez des accolades dans votre expression if, ces chaînes ne sont pas évaluées mais sont simplement interprétées telles quelles - en tant que chaîne de caractères.

1
bmk

Dans ($number == 1), 1 est attribué et la comparaison est effectuée.Ex: 1==1 ici, la sortie est booléenne . Mais dans {$number == 1 && $name == "hello"}, $ numéro n'est pas attribué car le support de fleur $number est comparé à 1;.

1
fahad