Переименовать глобальный массив TCL

#arrays #tcl #global

#массивы #tcl #глобальный

Вопрос:

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

 array set DataReturn {
    red   1
    green 5
    blue  4
    white 9
}

proc _RenameArray {Arr NewArrName} {
    global $NewArrName
    upvar #0 $Arr $NewArrName
    array unset $Arr
}

_RenameArray DataReturn TheArr
  

Я знаю, что здесь мне многого не хватает. будем признательны за любую помощь!

Комментарии:

1. @DonalF могли бы вы помочь в этом?

Ответ №1:

Это зависит. Переменные Tcl нельзя переименовать, не совсем, но они могут эффективно иметь несколько имен. Вы создаете их с помощью upvar . В частности, upvar 0 присвоит другое имя переменной в текущей области видимости.

 upvar 0 DataReturn TheArr
  

По сути, это создает TheArr связанную переменную; ее реальное содержимое является указателем на другую переменную (которая, конечно, может быть массивом), но любое действие над связанной переменной преобразуется в действие над базовой переменной (за исключением изменения ссылки, указывающей на что-то другое). Единственный способ, которым это не является переименованием, заключается в том, что исходная переменная все еще существует и не может быть удалена.

Если вы не можете этого сделать, ваш единственный вариант — скопировать переменную в другую переменную и unset в исходную. Это тривиально для простых переменных:

 set TheNew $TheOld
unset TheOld
  

и лишь немного сложнее для массивов:

 array set TheNew [array get TheOld]
unset TheOld
  

Однако при этом не сохраняются переменные, которые связываются с массивом, или любые заданные трассировки. Копировать-удалить — это не то же самое, что переименовать.


Преобразование объектов в процедуры немного сложнее, поскольку разрешение имен переменных зависит от контекста, в котором это выполняется. Таким образом, потенциально требуется некоторая осторожность с upvar и uplevel . Я не буду обсуждать эти параметры; суть операции в том, о чем я говорил выше, но они выполняются контекстно-зависимым способом ( "#0" заключен в кавычки из-за подсветки синтаксиса здесь):

 proc RenameGlobalVariable {OldName NewName} {
    uplevel "#0" [list upvar 0 $OldName $NewName]
}
  
 proc RenameGlobalSimpleVariable {OldName NewName} {
    upvar "#0" $OldName old $NewName new
    set new $old
    unset old
}
  
 proc RenameGlobalArray {OldName NewName} {
    upvar "#0" OldName old $NewName new
    array set new [array get old]
    unset old
}
  

Комментарии:

1. Конечно, легко скопировать трассировки из одной переменной в другую (по модулю некоторых граничных условий). Чтобы скопировать трассировки, установленные на foo в bar , просто используйте foreach ti [trace info variable foo] {trace add variable bar {*}$ti} .

2. @Donal Спасибо, я ценю помощь!

Ответ №2:

Это можно упростить:

 proc _RenameArray {Arr NewArrName} {
  upvar $Arr Temp
  global $NewArrName
  array set $NewArrName [array get Temp]
  uplevel #0 array unset Temp
}
  

Комментарии:

1. Спасибо! Я ценю обзор кода. Я всегда стремлюсь оптимизировать свой код! Я уверен, что удаление foreach немного ускорит процесс.

Ответ №3:

После того, как я некоторое время бился головой о свой стол, я получил это.

 proc _RenameArray {Arr NewArrName} {
    global [subst $NewArrName];
    upvar #0 $Arr Temp;
    foreach {Key Value} [array get Temp] {
        set [subst $NewArrName]($Key) $Value
    }
    uplevel #0 array unset $Arr
}
  

Кто-нибудь знает лучший способ сделать это, я весь внимание!