TCL: Как найти конкретное имя переменной, возвращаясь в кадрах из текущей точки выполнения, а затем получить ее значение? - PullRequest
1 голос
/ 08 июля 2019

У меня есть некоторый код, который выполняется изнутри процедуры, но на один уровень выше.

, например

proc foo {} {
  set <unique_var_name> <some value>
  uplevel 1 {<script>}
}

<script> может быть любым кодом и может содержать несколько вызовов proc.

Я хочу написать еще одну процедуру 'get_ <unique_var_name>', которую можно вызывать из любого места в пределах <script> и возвращать все, что <unique_var_name> установлено в foo, т.е. <some_value>

Полагаю, мне нужно возвращаться назад на один кадр за раз, а затем каким-то образом проверять наличие <unique_var_name>, но как это можно сделать?

Ответы [ 2 ]

0 голосов
/ 09 июля 2019

Когда вы uplevel (до уровня, отличного от вашего), код, который вы там запускаете, не может получить доступ к локальным переменным команды, которая выполняет uplevel. Там нет uplevel -1 или upvar -1. Это потому, что вы можете тривиально вызвать код, который выполняет другой uplevel, и нет способа описать, какая ветвь дерева должна идти вниз:

originalCall
     |______________
     |     |        |
    foo   get   something

Если у вас есть какой-то токен состояния (например, имя переменной, которое невозможно угадать), вам придется явно указать это сценарию, который foo использует для запуска uplevel. Вы можете сделать это, добавив его в качестве элемента списка (действительно полезно только для стиля сценария «командный префикс»), подставив его перед запуском или установив значение переменной вызывающего в значение. Этот третий случай является одним из основных применений для upvar, и он очень хорошо работает в терминах API, если вызывающий абонент назначает переменную для записи:

proc foo {varName} {
  upvar 1 $varName var
  # You can keep your own private copy as well; that's trivial
  set var <someValue>
  uplevel 1 {<script>}
}

Конечно, это означает, что вызывающий должен управлять уникальностью и т. Д.… Но на практике это действительно легко.

0 голосов
/ 09 июля 2019

В Tcl вы не можете перейти в «нижний» фрейм стека или связать переменные таким образом (например, с имитацией языков, имеющих лексическую область видимости).uplevel является односторонней, т. Е. Восходящей операцией.

proc foo {} {
    set XXX 1
    uplevel 1 {
      puts [get_XXX]
    }
}

proc get_XXX {} {
    uplevel 1 set XXX
}

foo

Здесь uplevel 1 в get_XXX будет указывать на кадр вызывающего абонента get_XXX, который является кадром вызывающего абонента.foo (и НЕ foo сам как вызывающий).

Возможная альтернатива

set XXX 2

proc foo {} {
    uplevel 1 {apply {{XXX} {
        upvar 1 XXX globalXXX
        puts $globalXXX
        puts [get_XXX]
    }} 1}
}

proc get_XXX {} {
    uplevel 1 set XXX
}

foo

Используя лямбду Tcl (apply), вы можете создать выделенный контекст выполнения, который может обращаться как к уровню общего вызова (globalXXX), так и к"местный" XXX.

...