Tcl upvar выпуск

Я пытаюсь изменить переменную, используя upvar (в восходящем стеке), но значение переменной передается в процедуру, а не имя переменной.

Я не могу изменить то, что пропущено, так как это уже широко реализовано в программе.

Есть ли способ изменить имя файла каким-либо образом?

proc check_file_exists {name} {
   upvar $name newName
   check_exists $name     #Do all checks that file is there
   set newName $name_1
}

check_file_exists $name
puts $name 

этот код напечатает старое имя файла, а не новое.

2 ответа

Решение

То, что я думаю, вы должны сделать, это укусить пулю и изменить вызовы. В конце концов, это довольно простой поиск и замена. Код будет более вменяемым, чем если бы вы использовали любое из других решений.

check_file_exists name

Или вы можете добавить другой параметр в список параметров и использовать его для передачи имени, делая первый аргумент фиктивным аргументом.

check_file_exists $name name

Или, если вы не используете возвращаемое значение, вы можете вернуть новое значение и присвоить его обратно:

set name [check_file_exists $name]

Или вы можете присвоить новое значение глобальной переменной (например, theValue) внутри процедуры и присвойте это обратно:

check_file_exists $name
# don't need this if you're in global scope
global theValue
set name $theValue

Или вы можете присвоить имя глобальной переменной (например, theName) и доступ к нему внутри процедуры: процедура сможет обновить name непосредственно.

# don't need this if you're in global scope
global theName
set theName name
check_file_exists $name

(Есть несколько вариантов использования upvar.)

Ни одна из альтернатив не хороша, и все они по-прежнему требуют внесения изменений при вызове (кроме последнего, если вы когда-либо используете только одну переменную для этого значения). Если вы непреклонны в том, что не делаете этого, всегда есть Донал info frame решение, которое требует только изменения самой процедуры.

Дайте мне знать, если вы хотите помочь с кодом процедуры для любой из этих альтернатив.

Это довольно сложно; это действительно не так, как вы должны работать. Но вы можете сделать это с помощью info frame -1 (средство, обычно используемое для отладки), чтобы точно узнать, как была вызвана текущая процедура. Однако вы должны быть осторожны, так как вызывающий может использовать результат команды: это небезопасный взлом.

proc check_file_exists {name} {
    set caller [dict get [info frame -1] cmd]
    if {[regexp {^check_file_exists +\$(\w+)} $caller -> varName]} {
        # OK, we were called with a simple variable name
        puts "Called with variable $varName"
    } else {
        # Complicated case! Help...
        return -code error "must be called with a simple variable's contents"
    }

    upvar 1 $varName newName
    check_exists $name
    set newName $name_1
}
Другие вопросы по тегам