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
}