Подстановка переменных в фигурных скобках в Tcl

Поправь меня, где я не прав.

Когда мы используем переменные внутри фигурных скобок, значение не будет заменено во время оценки и будет просто передано в качестве аргумента в процедуру / команду. (Да, есть некоторые исключения, такие как expr {$x+$y}).

Рассмотрим следующие сценарии,

Сценарий 1

% set a 10
10
%  if {$a==10} {puts "value is $a"}
value is 10
%  if "$a==10" "puts \"value is $a\""
value is 10

Сценарий 2

%  proc x {} {
        set c 10
        uplevel {set val $c}
}
%
% proc y {} {
         set c 10
        uplevel "set val $c"
}
% x
can't read "c": no such variable
% y
10
% set val
10
%

В обоих сценариях мы можем видеть, что подстановка переменной выполняется в теле if петля (то есть {puts "value is $a"}), тогда как в uplevelэто не так (т.е. {set val $c}), основываясь на текущем контексте.

Я вижу это так, как будто они могут получить к нему доступ через upvar такие вещи могут быть. Но почему это должно быть по-разному в разных местах? За кулисами, почему он должен быть разработан таким образом? Или это просто обычный способ, как Tcl работает?

2 ответа

Решение

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

Но некоторые команды отправляют полученное слово снова. Например:

eval {
    puts "this is an example with your path: $env(PATH)"
}

Правило относится к внешнему eval, но это объединяет свои аргументы и затем снова отправляет результаты в Tcl. if делает нечто подобное со своим сценарием тела, за исключением того, что нет конкатенации, а вместо этого есть условное выполнение. proc также делает то же самое, за исключением того, что задерживает выполнение кода до тех пор, пока вы не вызовете процедуру. expr команда как evalза исключением того, что отправляет скрипт в механизм оценки выражений, который на самом деле является отдельным небольшим языком. if Команда также использует механизм выражений (как и while а также for). Язык выражения понимает $var (а также […]) также.

Так что произойдет, если вы сделаете это?

set x [expr $x + $y]

Ну, сначала мы разберем первое слово, set, затем xзатем третьим словом запускаем подстановку команд, которая рекурсивно входит в парсер до совпадения ] найден. С внутренней exprмы сначала разберемся expr, затем $x (читая x переменная), то +, затем $y, Теперь expr команда вызывается с тремя аргументами; он объединяет значения с пробелами между ними и отправляет результат объединения в механизм выражений. Если у тебя есть x ранее содержащий $ab а также y содержащий [kaboom], выражение для оценки будет на самом деле:

$ab + [kaboom]

что, вероятно, даст вам ошибку о несуществующей переменной или команде. С другой стороны, если вы сделали expr {$x + $y} с фигурными скобками вы получите дополнение, примененное к содержимому двух переменных (в данном случае это ошибка, поскольку ни одна из них не похожа на число).


Рекомендуется заключать выражения в скобки, потому что тогда написанное вами выражение будет выражением, которое будет оценено. В противном случае вы можете получить все виды "неожиданного" поведения. Вот мягкий пример:

set x {12 + 34}
puts [expr $x]
set y {56 + 78}
puts [expr $y]
puts [expr $x * $y]

Помните, что Tcl всегда работает одинаково. Никаких особых случаев. Все, что выглядит как особые случаи, - это просто команда, которая реализует небольшой язык (часто путем рекурсивного вызова обратно в Tcl или механизм выражений).

В дополнение к ответу Donal Fellows:

В сценарии 2, в x команда uplevel {set val $c} вызывается и завершается ошибкой, потому что на уровне вызывающей стороны такой переменной нет.

В y, эквивалент uplevel {set val 10} вызывается (потому что значение c заменяется при интерпретации команды). Этот скрипт может быть оценен на уровне вызывающего, так как он не зависит от каких-либо переменных там. Вместо этого он создает переменную val на этом уровне.

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

Теперь попробуйте это:

% set c 30
30
% x
30
% y
10

Если на уровне вызывающего есть такая переменная, x полезная команда для установки переменной val к стоимости c, в то время как y полезная команда для установки переменной val к значению, заключенному внутри y,

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