过程基础:
过程由 proc 命令创建,格式如下:
proc 过程名 参数列表 过程体
实例如下:
proc plus {a b} {expr {$a + $b}}
plus命令的返回值就是它的过程块中最有一个命令的返回值。
可以用return提前返回, return 的参数就是该过程的返回值。下面是使用return命令的阶乘功能实现:
proc fac {x} {
if {$x <= 1} {
return 1;
}
return [ expr {$x * [fac [expr {$x - 1}]]}]
}
fac 4
=>24
fac 0
=>1
局部和全局变量:
过程可以使用 global 命令引用全局变量。例如,下面这条命令让全局变量x y在过程中可见
global x y
global命令把它的每一个参数作为全局变量的名称对待,将过程中对这些变量名的引用定向到全局变量而非局部变量。
global命令可以在过程中的任何时候调用;一旦调用,它就会一直有效,知道过程返回。
参数个数和默认值设置:
过程可以有0个参数,只需要参数列表为 {} 即可:
proc printVars {} {
puts "a is $a,b is $b"
}
设置参数默认值:
proc inc {value {increment 1}} {
expr $value+$increment
}
该过程有两个参数,一个固定参数value,一个可选参数increment,默认值是1。
可选参数在调用时可以不必给出。
inc 42 3
=>45
inc 42
=>43
默认参数必须放在参数列表的尾部。如果一个参数是默认参数,那么参数列表中它后面的参数都必须是默认参数。
特殊参数 args ;
如果参数列表中最后一个参数是特殊名称args,那么可以给出可变数量个参数。
例如下面这个过程,获取任意个参数,返回它们的和:
proc sum {base args} {
set total 0
foreach val $args {
set total [ expr {$total + $val}]
}
return [expr {$base + $total}]
}
其中base参数必须给出。使用如下:
sum 1
=>1
sum 1 2
=>3
sum 1 2 3
=>6
sum
=>wrong # args: should be "sum base ?arg ...?"
提示错误,base参数未指定。
传引用调用upvar:
可以用 upvar 命令模拟传引用调用的行为,这对数组特别有用。如果a是一个数组,就不能像myproc $a这样把它传给过程myproc,因为并没有
对应整个数组的值;只有对应各个数组元素的值。
但是可以把数组名传给过程,myproc a,然后使用upvar命令在过程中访问数组的元素。
下面是在过程中使用upvar的简单示例,输出一个数组的内容:
proc printArray {name} {
upvar $name a
foreach el [ lsort [ array names a]] {
puts "$el=$a($el)"
}
}
set info(age) 37
set info(position) "vice president"
printArray info
=>age=37
position=vice president
上述代码中upvar命令使得过程可以通过变量a访问这个数组。
应用匿名过程:
apply {argList body ?namespace?} ?arg1 arg2 arg3 ...?
argList是过程的形参,body是实现过程块的tcl脚本,?namespace?是可选的,指明运行过程的命名空间。
?arg1 arg2 arg3 ...?是赋给过程参数的值。
下面这个匿名过程对一下数求和:
apply {{args} {
set total 0
foreach val $args {
set total [expr {$total + $val}]
}
return $total
}} 1 2 3 4 5 6 7
=>28
它把1 2 3 4 5 6 7作为一个列表传给过程的形参args,然后匿名过程计算并返回这些值的和。
一个更有代表性的例子,考虑对一个列表依据各个元素的字符串长度排序。lsort命令的-command选项可以指定自己的排序过程。
set states {333 22 4444 1}
lsort -command {apply {{e1 e2} {
expr {[ string length $e1] - [string length $e2]}
}
}
} $states
=>1 22 333 4444
apply 可以用于创建实现不同功能的结构块。下面的代码展示了map命令的实现。
proc map {lambda list} {
set result {}
foreach el $list {
lappend result [apply $lambda $el]
}
return $result
}
map {x {expr {$x*$x}}} {1 2 3 4}
=>1 4 9 16
map {x {return [ list [string length $x] $x]}} {a bb ccc dddd}
=>{1 a} {2 bb} {3 ccc} {4 dddd}