set gvar "Hello World" puts $gvar ;# global宣言は不要 proc foo {} { global gvar puts $gvar ;# global宣言は必要 } |
Tcl8.0からは、namespaceのスコープ解決演算子(::)を使って完結に書くこともできます。
この場合、global宣言が不要ですっきりします。
set gvar "Hello World" proc foo {} { puts $::gvar } |
set gvar "Hello World" proc foo {arg} { upvar $arg var set var "Good Morning" } foo gvar puts $gvar |
upvarの第1引数にnumberを指定すると、レベルを指定できます。
1を指定すると1つ上のスコープという意味になります。
省略時のデフォルトは1です。
また、#numberを指定すると、globalスコープからの相対レベルになります。
globalスコープは#0になるので、globalコマンドは以下と同じ意味になります。
upvar #0 foo foo |
set gval {Hello World} proc foo {} { uplevel {set gval {Good Morning}} } foo puts $gvar |
uplevelの第1引数にnumberを指定すると、レベルを指定できます。
1を指定すると1つ上のスコープという意味になります。
省略時のデフォルトは1です。
また、#numberを指定すると、globalスコープからの相対レベルになります。
proc foo {} { set var "Hello World" after 1000 {puts $var} } foo |
解決策としては、変数varをafterコマンドに渡す前に展開する方法です。
# ちょっと複雑? proc foo {} { set var "Hello World" after 1000 "puts \"$var\"" } foo |
# ややシンプル? proc foo {} { set var "Hello World" after 1000 [list puts $var] } foo |
イベントハンドラでコマンドを起動するbindやbutton -command等も同様です。
特にダブルクォートを使うとコマンド置換と変数置換の結果が予測しにくくなり、
これによってスクリプトにバグが組み込まれてしまう可能性があります。
十分注意して使いましょう。