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

set list { 
      {/run      00}
      {/run/shm  00}
      {/boot     00}
}

И использовать следующий код как часть цикла foreach для увеличения значения ...

lset list 1 [expr {[lindex $list 1] + 1}]

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

Если я установить базовый прирост для стандартной переменной как часть кода ..

set counter 00
incr counter 

Он вполне счастливо увеличивается при каждом запуске кода, и счетчик увеличивается на 1, пока я не нарушу код.

Любой совет или помощь в получении этой работы будет принята с благодарностью. Я определенно не эксперт по Tcl, поэтому, если я пытаюсь сделать это неправильно, пожалуйста, дайте мне знать. :)

Заранее спасибо за вашу помощь.

0
Chris Davies 25 Апр 2020 в 20:27

2 ответа

Лучший ответ

Я ожидаю, что делать это:

for {set idx 0} {$idx < [llength $list]} {incr idx} {
    lset list $idx 1 [expr {[lindex $list $idx 1] + 1}]
}

Будет увеличивать каждое числовое значение в этом списке, что, как я полагаю, вы хотите сделать. Тем не менее, делая this:

foreach pair $list {
    lset pair 1 [expr {[lindex $pair 1] + 1}]
}

не будет работать. Tcl концептуально копирует элементы подсписка из основного списка в foreach, чтобы изменения в pair не отражались обратно. Кроме того, концептуально Tcl также копирует значение для передачи в foreach в первую очередь. Конечно, эти копии на самом деле не настоящие, так как это будет очень дорого! Вместо этого Tcl использует общие ссылки с семантикой «копировать при записи в общий», система, которая работает очень хорошо, учитывая, что мы можем очень дешево проверить состояние общего доступа (что обеспечивается моделью потоков Tcl; значения never разделяется между потоками, поэтому решения о состоянии совместного использования могут быть свободными от блокировки и локальными).

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

0
Donal Fellows 25 Апр 2020 в 17:45

Если вы слегка измените свою структуру данных, чтобы сгладить ее вместо использования списка пар, она станет пригодной для использования в качестве подсказки. И есть dict incr команда:

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

Пример использования:

% set list {/run 0 /run/shm 0 /boot 0}
/run 0 /run/shm 0 /boot 0
% dict incr list /boot
/run 0 /run/shm 0 /boot 1
% puts $list
/run 0 /run/shm 0 /boot 1

Если вы хотите сделать это в команде, вы должны передать по имени и использовать upvar поэтому изменения вносятся в правый кадр стека:

% proc demo {fstab_} {
    upvar 1 $fstab_ fstab
    dict incr fstab /run
  }
% demo list
/run 1 /run/shm 0 /boot 1
% puts $list
/run 1 /run/shm 0 /boot 1

И чтобы обновить каждое значение:

% foreach dir [dict keys $list] { dict incr list $dir }
% puts $list
/run 2 /run/shm 1 /boot 2
1
Shawn 25 Апр 2020 в 20:51