流程控制命令
請參考 F-F 乘法表 與 Random Walk 兩個程式. 後者可與 C 版本的 Random Walk 對照. 可以在 tclsh 的命令列下用 "source 檔案名稱" 載入程式執行; 如果你用的是 UNIX 版的 Tcl/Tk, 也可以直接在 shell 的命令列下打入檔案名稱執行. (要先 "chmod u+x 檔案名稱", 並用 "which tclsh" 確定你的 tclsh 安裝的地點與我的相同.)
- Tcl parser 並不認識流程控制命令, 照舊把它們當做一般的命令. 就像在 puts {hello, world} 這句話當中, puts 接受一個參數一樣, 在 if {3>2} {puts hello} 這句話當中, if 接受兩個參數. 因此在 Tcl/Tk 程式中, 流程控制命令的左大括弧不可以放在換列之後, 否則會被視為另一個命令的開始.
-
常用流程控制命令:
- if 判斷條件 執行內容 elseif 判斷條件 執行內容 ... else 執行內容
- while 繼續條件 迴圈內容
- for 起始設定 繼續條件 遞增動作 迴圈內容
- break
(跳出最內層迴圈) - continue
(略過最內層迴圈的目前這次, 繼續執行最內層迴圈的下一次) - switch 字串 { 樣版 執行內容 樣版 執行內容 ... }
(會 C 語言者請注意: 不需要 break)
- 以上 if 的 "判斷條件", while 的 "繼續條件", for 的 "繼續條件" 都是由 expr 命令處理的; 而 if 的 "執行內容", while 的 "迴圈內容", for 的 "迴圈內容", switch 的 "執行內容" 都是由 eval 命令處理的.
-
使用者自定命令 (即副程式): proc
- 語法: proc 新副程式名稱 參數列 執行內容
-
副程式內的變數都是局部變數, 連參數也是. 再加上參數是以值傳遞,
所以副程式可以遞迴, 例如:
proc fact {n} { if {$n <= 0} { return 1 } else { set f [fact [expr $n - 1]] return [expr $n * $f] } # return [expr $n>0 ? [fact [expr $n - 1]] * $n : 1] }
要用全域變數則必須以 global 宣告. - return 可以讓控制流程從副程式當中轉回呼叫程式; 如果沒有 return, 則以副程式中最後一個命令的傳回值作為副程式的傳回值.
- 參數的內定值: 用重疊的串列 (nested list) 表示. (講到 list 再詳述)
- 可以接受不定個數參數的副程式: 把最後一個參數取名為 args. (講到 list 再詳述)
-
如何以名傳遞 (call by name, 有點像是 C++ 當中的 call by
reference, 但不完全相同)? 用 upvar. 例如想寫一個副程式 swap
用來交換兩個變數的內容:
錯誤示範: proc swap {a b} { set tmp $a set a $b set b $tmp return "" } 正確寫法: proc swap {a b} { upvar $a ra $b rb set tmp $ra set ra $rb set rb $tmp return "" }
測試: set x 5 ; set y 3 ; swap x y ; puts "$x $y"
(特別注意何時需要 $ 何時不需要 $) -
陣列無法以值傳遞, 一定要用 upvar 以名傳遞.
proc total arr { upvar $arr rarr set ans 0 foreach el [array names rarr] { incr ans $rarr($el) } return $ans }
測試: set a(1) 3 ; set a(2) 18 ; set a(3) 7 ; total a
(特別注意何時需要 $ 何時不需要 $)
-
參考範例使用到的其他功能
- 在 UNIX 的多數 shells (例如 bash 或 tcsh) 底下, 下 chmod u+x ... 命令可以把純文字檔變成可執行的批次檔. 而且檔案裡面也不一定非得是 shell 的命令不可, 只要第一列是: #!.... 就可以改變批次檔裡面所使用的語言.
- 在支援 ANSI escape sequence 的視窗/終端機上印 "ESC[..." 這類字串, 可以控制遊標的位置, 改變字元的顏色 ... 等等. 很多 bbs 與 mud 的效果都是用這個作出來的. (help: 幫我找一個 url 吧, 謝謝!)
- 在很多程式語言當中都是這樣: 因為檔案輸入輸出都經過 buffer (以便一次大量處理, 較有效率), 如果你希望印出去的 ANSI escape sequence 立即生效, 必須用 flush 強迫系統立即處理.
- 檢查系統內定變數 tcl_interactive 可以知道這個程式現在究竟是否正在交談模式下執行.
-
作業: 計算 房屋貸款付款表. (or
here) 公式: A/P = i * (1+i)^n / (
(1+i)^n - 1 ) 其中
- A/P 為每期付款/貸款總額比例, 在範例中取 P=10000 (貸款總額一萬元)
- i 為每期利率. 在範例中最左列印出來的是年利率, 但是計算時每月複利一次, 所以如果要算 5.0% 那一列, i 要用 0.05/12
- n 為總期數. 如果要算 30 年那一行, n 要用 30*12
- 本頁最新版網址: https://frdm.cyut.edu.tw/~ckhung/b/tcl/control.php; 您所看到的版本: February 14 2012 10:32:25.
- 作者: 朝陽科技大學 資訊管理系 洪朝貴
- 寶貝你我的地球, 請 減少列印, 多用背面, 丟棄時做垃圾分類。
- 本文件以 Creative Commons Attribution-ShareAlike License 或以 Free Document License 方式公開授權大眾自由複製/修改/散佈。