Невозможно изменить значение переменной
Я использую симулятор дискретных событий под названием ns-2, который был построен с использованием Tcl и C++. Я пытался написать некоторый код в TCL:
set ns [new Simulator]
set state 0
$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 2.0 "puts \"At 2.0 values of state is: $state\""
proc changeVal {} {
global state
global ns
$ns at-now "set state [expr $state+1]"
puts "Changed value of state to $state"
}
$ns run
Вот вывод:
At 0.0 value of state is: 0
Changed value of state to 0
At 2.0 values of state is: 0
Ценность государства, похоже, не меняется. Я не уверен, что делаю что-то не так при использовании TCL. У кого-нибудь есть идея относительно того, что здесь может пойти не так?
РЕДАКТИРОВАТЬ: Спасибо за помощь. На самом деле, ns-2 - это то, над чем у меня нет особого контроля (если я не перекомпилирую сам симулятор). Я опробовал предложения и вот вывод:
для кода:
set ns [new Simulator]
set state 0
$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 9.0 "puts \"At 2.0 values of state is: $state\""
proc changeVal {} {
global ns
set ::state [expr {$::state+1}]
$ns at-now "puts \"At [$ns now] changed value of state to $::state\""
}
$ns run
выход:
At 0.0 value of state is: 0
At 1 changed value of state to 1
At 2.0 values of state is: 0
И для кода:
set ns [new Simulator]
set state 0
$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 9.0 "puts \"At 2.0 values of state is: $state\""
proc changeVal {} {
global ns
set ::state [expr {$::state+1}]
$ns at 1.0 {puts "At 1.0 values of state is: $::state"}
}
$ns run
выход:
At 0.0 value of state is: 0
At 1.0 values of state is: 1
At 2.0 values of state is: 0
Кажется, не работает... Не уверен, если это проблема с NS2 или мой код...
3 ответа
Изменить: теперь понимание конечного автомата
Во-первых, синтаксис цитирования, который вы используете, доставит вам неприятности. Обычно вы должны создавать команды Tcl, используя список, это гарантирует, что Tcl не будет расширять то, что вы не хотите, чтобы он расширял.
Ваш at-now
вызовы заменяют state
переменная, когда вы делаете вызов (то есть, когда значение не изменяется и 0. То, что вы хотите, это:
$ns at-now 0.0 {puts "At 0.0 value of state is: $::state"}
$ns at-now 2.0 {puts "At 2.0 value of state is: $::state"}
Похоже, ваш changeVal
написано правильно (в первой версии были некоторые из тех же проблем замещения), а также тот факт, что вы передавали переменные ссылки, которые будут использоваться локально, и, следовательно, не устанавливали глобальное состояние.
Решение части первой версии вопроса - используйте глобальные ссылки и укажите оба [
а также $
для предотвращения замены в точке вызова:
$ns at-now "set ::state \[expr {\$::state + 1}\]"
или, используя фигурные скобки:
$ns at-now {set ::state [expr {$::state + 1}]}
Проблема в том, что вы подставляете значение своих переменных немедленно, а не во время оценки кода. Вам нужно отложить замену. Таким образом, вместо:
$ns at 2.0 "puts \"At 2.0 values of state is: $state\""
Сделай это:
$ns at 2.0 {puts "At 2.0 values of state is: $state"}
Хорошей практикой является введение в процедуру чего-либо более сложного, чем простой вызов команды без подстановки, когда выполняется такой вызов. Гораздо проще заставить его работать правильно.
[РЕДАКТИРОВАТЬ]
Так же at-now
все еще откладывает делать свое тело до окончания текущего at
возвращается.
Я не уверен, почему это работает, но это работает:
set ns [new Simulator]
set state 0
proc changeVal {} {
global ns
incr ::state
$ns at-now {puts "Local::At [$ns now] values of state is: $::state"}
}
$ns at 0.0 "puts \"Global::At 0.0 value of state is: $state\""
changeVal
$ns at 9.0 "puts \"Global::At 2.0 values of state is: $state\""
$ns run
Выход:
Global::At 0.0 value of state is: 0
Local::At 0 values of state is: 1
Global::At 2.0 values of state is: 1
Если кто-нибудь знает объяснение, это было бы здорово.