Оператор if в TCL

У меня есть вопрос об утверждении if в tcl следующего кода:

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 как ожидается, будет логическим, почему? Разве второе не является допустимым выражением? Как это исправить?

4 ответа

Решение

Брекеты, {}и скобки, (), не являются взаимозаменяемыми в Tcl.

Формально фигурные скобки (за одним исключением) являются своего рода цитированием, которое указывает, что никакие дальнейшие замены не должны выполняться для содержимого. В первом случае выше это означает, что этот аргумент доставляется if без подстановки, которая оценивает его как выражение. У подъязыка выражения есть сильно аналогичная схема интерпретации скобок к общему Tcl; они обозначают буквальное значение без дальнейших подстановок.

Напротив, круглые скобки в основном не являются специальными в Tcl. Исключение составляют имена элементов массивов (например, $foo(bar)), в подъязыке выражений (который использует их для группировки, как в математических выражениях по всему программированию) и в подъязыке регулярных выражений (где они представляют собой другой тип группировки и несколько других вещей). Вполне законно использовать круглые скобки - сбалансированные или иные - как часть имени команды в Tcl, но ваши коллеги-программисты могут в любом случае жаловаться на вас за написание непонятного кода.

Особенности

В этом конкретном случае тестовое выражение этого if:

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

разбирается на:

бла #1 LOGICAL_OR бла #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, и мы постараемся найти лучший путь; почти всегда есть один доступный.

В ($number == 1) номеру присваивается 1 и производится сравнение. Пример: 1==1 здесь вывод является логическим. Но в {$number == 1 && $name == "hello"} $ номер не назначен из-за цветочной скобки $number по сравнению с 1 поэтому полученный результат не является логическим.

Я думаю, что сообщение об ошибке, которое вы получаете, не означает, что $number должен быть логическим (я получил сообщение expected boolean value but got "$number == 1 && $name == "hello""). Это означает, что строка $number == 1 && $name == "hello" не является логическим значением - что, безусловно, верно. Если вы используете фигурные скобки в вашем if Выражение этих строк не оценивается, а просто интерпретируется как строка символов.

Короче: if использует специальный "мини язык" для своего сценария условия - то же самое, что понимают expr командование Это указано в if страница справочника:

Команда if оценивает expr1 как выражение (так же, как expr оценивает свой аргумент).

В отличие от самого Tcl, который довольно похож на LISP и / или похож на оболочку Unix, это "expr мини-язык "более" традиционен "в том смысле, что он похож на C.

Другие вопросы по тегам