оператор 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
таким образом, полученный вывод не является логическим.