оператор 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 ответов


брекеты {} и скобки, (), are не заменимый в Tcl.

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

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

Особенности

в этом конкретном случае тестовое выражение this 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"}]} {...}

это обычно не хорошая идея-дополнительная масса без дополнительной выгоды , но это имеет смысл там, где вы попытка использовать динамически сгенерированное выражение в качестве условия тестирования. не делай этого если вы действительно не уверены, что вам нужно это сделать! Я серьезно. Это очень продвинутая техника, которая вам вряд ли когда-либо понадобится, и часто есть лучший способ сделать вашу общую цель. Если вы думаете, что вы может нужно, ради бога, спросите здесь, и мы постараемся найти лучший способ; почти всегда есть один доступный.


Я думаю, что сообщение об ошибке вы получаете не означает, что $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.


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