TCL有一些函数指针的概念吗?

时间:2008-10-31 13:19:34

标签: design-patterns function-pointers tcl

使用TCL,我想实现像Strategy Pattern这样的东西。我想在TCL功能中传递打印输出的“策略”,因此我可以轻松地在打印到屏幕之间切换并打印到日志文件。在TCL中这样做的最佳方式是什么?

8 个答案:

答案 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与%的命令参数替换相同的方式。您可以尝试使用uplevelupvar来做一些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(已经有一段时间......)但也许其中一个可以满足您的需求:

  • [$ var param1 param2]
  • [$ var] param1 param2
  • $ var param1 param2

如果我错了,任何人都可以自由纠正我。

答案 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
一帆风顺。