为什么我们需要在tcl中嵌套过程

时间:2013-06-20 16:26:53

标签: nested tcl procedures

您好我一直在使用tcl脚本近一年,现在完全了解它的基本知识。但今天我刚刚遇到嵌套程序,这有点奇怪,因为我没有使用它。

无论如何,我读到了关于嵌套proc here的内容,但是我们为什么不需要它,因此没有明确的想法。

文章说,因为proc在命名空间中是全局的,所以要创建一个本地proc,你可以创建嵌套的proc。

    proc parent {} {
        proc child {} {
            puts "Inside child proc";
        }
        ...   
    }

现在我能想到的一种用法就像是

    proc parent {} {
        proc child {intVal} {
            puts "intVal is $intVal";
        }
        puts "[::child 10]";
        ... #some processing
        puts "[::child 20]";
        ... #some processing
        puts "[::child 30]";
        ... #some processing
        puts "[::child 40]";
        ... #some processing
        puts "[::child 50]";
        ... #some processing
    }

所以现在子proc是父proc的本地,并且只能在parent proc中使用。而且据我所知,当你想在父proc中的多个地方进行相同的处理时它很有用。

现在我的困惑是,这是嵌套proc的唯一用途还是还有其他我不理解的东西???我的意思是嵌套proc似乎是一种私有过程。

所以请详细说明并帮助我理解嵌套过程的使用。

2 个答案:

答案 0 :(得分:7)

Tcl没有嵌套程序。您可以在过程定义中调用proc,但这只是创建一个正常的过程(用于解析要创建的过程名称的命名空间将是调用者的当前命名空间,如{{1}所报告的})。

为什么要将namespace current放在proc内?那么,这样做的真正原因是当你想让外部命令充当 factory 时,在调用它时创建命令。有时,要创建的命令的名称将由调用者提供,有时它将在内部生成(在后一种情况下,返回创建的命令的名称是正常的)。出现的另一种情况是外部命令是(真实的)内部命令的某种代理,允许推迟创建真实命令,因为它在某种程度上是昂贵的;如果是这种情况,内部过程将倾向于实际使用同名创建外部过程,并且它将替换它(虽然不是执行堆栈框架; Tcl小心那个因为那会否则就疯了。

如果你真的需要一个“内部程序”,那么最好使用一个lambda术语,你可以proc 代替。这是因为它是一个真正的值,可以存储在局部变量中,当外部过程终止时(或者如果你明确地apply变量或替换它的内容)它将自动消失。除了unset之外,这个内部代码无法访问外部代码的变量;如果你想在仍然绑定变量时返回值,你应该使用命令前缀并包含一些额外的技巧来将变量绑定为预先提供的参数:

upvar

使用内部proc multipliers {from to} { set result {} for {set i $from} {$i <= $to} {incr i} { lappend result [list apply {{i n} { return [expr {$i * $n}] }} $i] } return $result } set mults [multipliers 1 5] foreach m $mults { puts [{*}$m 2.5] } # Prints (one per line): 2.5 5.0 7.5 10.0 12.5 来模拟proc

请注意,apply命令实际上可以由内部过程模拟。这是Tcl 8.4及之前使用的一种技术:

apply

这有点容易出错并且非常慢,因为它会在每次调用时重新编译;我们不再这样做了!

答案 1 :(得分:1)

Tcl没有嵌套的过程。从proc手册页:

  

通常,name是不合格的(不包括任何包含名称空间的名称),在当前名称空间中创建新过程

(强调我的)

演示:

% namespace eval foo {
    proc parent {} {
        proc child {} {
            puts "the child"
        }
        puts "the parent, which holds [child]"
    }
}
% foo::parent
the child
the parent, which holds 
% foo::child
the child

我们仍然可以直接调用“内部”过程 - 它不是封闭过程的本地。

你在wiki页面的讨论中遗漏的一个项目是,为了使proc只对封闭的proc进行本地操作,必须在封闭的proc的末尾删除它:

% namespace eval foo {
    proc parent {} {
        proc child {} {
            puts "the child"
        }
        puts "the parent, which holds [child]"
        # now, destroy the inner proc
        rename child ""
    }
}
% foo::parent
the child
the parent, which holds 
% foo::child
invalid command name "foo::child"

关于本地proc的使用,我同意你的看法,封装只在当前proc中有用的重复任务是有益的。我不会太过于沉溺于此:明确的文档或代码约定也会这样做。