这是Tcl 8.4。
我正在尝试创建一个可以在用户指定的任何其他过程上执行常见操作的过程。
例如:
proc process_menu_item {command args {count 1}} {
set inf [expr {$count == -1 ? 1 : 0}]
set end_str [expr {$count == -1 ? "inf" : $count}]
set loop_cnt 0
while {$inf || $count > 0} {
incr loop_cnt
puts [format "------- %s -------" [bold "LOOP $loop_cnt of $end_str"]]
$command $args
}
return
}
我希望这个程序只执行指定的$ command $ count次。 我遇到的问题是传递参数。
我们假设我想调用这样的程序:
proc example {{par_a {-1}} {par_b {-1}} {par_c 1}} {
puts "All params: $par_a $par_b $par_c"
}
我该如何致电process_menu_item
?它甚至可能吗?我尝试了一个字符串,一个列表,但最终par_a
获得了所有参数的大列表。
谢谢。
答案 0 :(得分:4)
(首先,程序的args
参数只有在最后一个时才是神奇的。把它放在它之后它变成一个普通的变量。就这样你知道。当然,这甚至可能是什么你需要在这里!)
要呼叫process_menu_item
,您需要更改:
$command $args
到此(Tcl 8.4或更早版本):
eval $command $args
好吧,如果你是偏执狂,你实际上是这样写的:
eval [list $command] [lrange $args 0 end]
或者您使用Tcl 8.5(或更高版本):
$command {*}$args
然后,你可能会像这样建立到 process_menu_item
的电话:
process_menu_item frobnicate [list foo bar]
还有其他一些方法可以实现,而不是使用list
(许多Tcl命令可以生成列表),或者您可以使用文字:
process_menu_item frobnicate {foo bar}
不建议将文字中的任何内容引用process_menu_item
内的变量(这只能使用最短的eval
形式)。它可以让你做出很棒的东西,但它也非常脆弱。如果你想传入循环变量,这很可能,但它需要更先进的技术(你应该问另一个问题)。
答案 1 :(得分:2)
您始终可以构建包装函数:
proc wrapper {arg_list} {
example [lindex $arg_list 0] [lindex $arg_list 1] [lindex $arg_list 2]
}
TCL 8.5的{*}
operator设计用于此类事情:
% proc test {a b c} {
puts a
puts b
puts c
}
%
% set inp [list "A" "B" "C"]
A B C
% test $inp
wrong # args: should be "test a b c"
% test {*}$inp
a
b
c
答案 2 :(得分:0)
我现在无法给出更全面的答案,但是interp alias
可能会让你到达目的地。有一个例子at rosettacode.org。如果这不适合,也许探索command traces - 为每个命令触发,你可以根据命令名做出选择。