使用TCL,我想实现像Strategy Pattern这样的东西。我想在TCL功能中传递打印输出的“策略”,因此我可以轻松地在打印到屏幕之间切换并打印到日志文件。在TCL中这样做的最佳方式是什么?
答案 0 :(得分:18)
TCL允许您将过程的名称存储在变量中,然后使用该变量调用过程;所以
proc A { x } {
puts $x
}
set strat A
$strat Hello
将调用proc A并打印出Hello
答案 1 :(得分:5)
除了显示如何为变量分配过程的答案之外,您还可以将过程的名称作为参数传递给另一个过程。这是一个简单的例子:
proc foo { a } {
puts "a = $a"
}
proc bar { b } {
puts "b = $b"
}
proc foobar { c } {
$c 1
}
foobar foo
foobar bar
这将打印a = 1和b = 1
答案 2 :(得分:4)
上面列出的一个稍微扩展的例子,可以更清楚地说明战略模式:
proc PrintToPDF {document} {
<snip logic>
}
proc PrintToScreen {document} {
<snip logic>
}
proc PrintToPrinter {document} {
<snip logic>
}
set document "my cool formatted document here"
set printMethod "printer"
switch -- $printMethod {
"printer" {
set pMethodName "PrintToPrinter"
}
"pdf" {
set pMethodName "PrintToScreen"
}
"screen" {
set pMethodName "PrintToPDF"
}
}
$pMethodName $document
答案 3 :(得分:3)
除了使用proc之外,您实际上可以使用代码块。这有一些变化。首先是最明显的,只是eval
。
set strategy {
puts $x
}
set x "Hello"
eval $strategy
unset x
这有效,但有一些缺点。首先显而易见的是,这两段代码必须串联起来使用参数的通用命名。这取代了一个名称空间头痛(procs)与另一个(本地人),这可能实际上更糟。
不太明显的是,eval在不编译字节码的情况下故意解释其参数。这是因为假设将使用动态生成的,通常是唯一的参数来调用eval,并且如果字节码仅使用一次,则编译为字节码将是低效的,相对于仅立即解释块。这更容易修复,所以这是成语:
set x "Hello"
if 1 $strategy
unset x
与if
不同, eval
会编译并缓存其代码块。如果$strategy
块只是一个或只是少数几个不同的可能值,那么这非常有效。
这对于使用局部变量将参数传递给块的可能性完全没有帮助。有很多方法可以解决这个问题,例如以substitutions执行tk与%
的命令参数替换相同的方式。您可以尝试使用uplevel
或upvar
来做一些hackish事情。例如,你可以这样做:
set strategy {
puts %x
}
if 1 [string map [list %% % %x Hello] $strategy]
关于传递的参数不会发生太大变化的可能性,这在字节码编译方面效果很好。另一方面,如果参数经常更改,则应使用eval
而不是if 1
。无论如何,就争论而言,这并没有好多少。因为你使用的是特殊的语法,所以对于通过什么和不通过什么的混淆的可能性较小。如果您想在返回代码块之前使用变量替换,这也很有用:如set strategy "$localvar %x"
中所示。
幸运的是,tcl 8.5使用apply
命令true anonymous functions。 apply命令的第一个单词是参数和正文的列表,就好像proc
的那些参数被解除了一样。其余参数立即作为参数传递给匿名命令。
set strategy [list {x} {
puts $x
}]
apply $strategy "Hello"
答案 4 :(得分:1)
如何使用变量函数?我不记得很多TCL(已经有一段时间......)但也许其中一个可以满足您的需求:
如果我错了,任何人都可以自由纠正我。
答案 5 :(得分:1)
% set val 4444
4444
% set pointer val
val
% eval puts $$pointer
4444
% puts [ set $pointer ]
4444
% set tmp [ set $pointer ]
4444
答案 6 :(得分:0)
为了澄清Jackson的方法有效,请记住在TCL中,所有都是一个字符串。无论您是使用文字字符串,函数,变量还是其他任何内容,所有都是字符串。您可以传递一个“函数指针”,就像您可以使用“数据指针”一样:只使用没有前导“$”的对象名称。
答案 7 :(得分:0)
以上所述,尽管从名称空间移动到名称空间时,您可能希望使用[namespace current ]::proc_name
作为传递,以确保您不会中断。
对于OO方法,您需要关注此帖子中的内容:Pass a method of a specific object as an input argument in Tcl
一帆风顺。