我想知道是否有人能解释为什么我可以成功地在嵌套TclOO中链接upvars的幕后细节,但是它不能在嵌套的方法中工作(这些方法在子类中被覆盖)。(有人告诉我,在TclOO类方法中调用next有点像“临时尾调用”,因为没有创建新的堆栈级别。是这个案子吗?如果是的话,全貌是什么?)
例如,以下三种方法并不都会产生相同的结果:
proc addone {varname} {
upvar $varname x;
incr x;
}
proc addanotherone {varname} {
upvar $varname xx;
addone xx;
incr xx;
}
oo::class create C1 {
method addone {varname} {
upvar $varname x;
incr x;
}
}
oo::class create S1 {
superclass C1;
method addone {varname} {
upvar $varname xx;
next xx;
incr xx;
}
}
oo::class create S2 {
superclass C1;
method addone {varname} {
upvar $varname xx;
next $varname;
incr xx;
}
}
set s1 [S1 new];
set s2 [S2 new];
set y 1;
addanotherone y;
set y; # First result gives 3, as expected;
set y 1;
$s1 addone y;
set y; # gives 2, unexpected;
set y 1;
$s2 addone y;
set y; #gives 3, unexpected, because original varname seems to be "two levels" deep.如果next以某种方式运行在相同的堆栈级别上,那么它能否在调用者作用域中创建变量而不使用"uplevel"?
如果不是的话,它并不是在同一水平上运行,那么它更像是一个闭包吗?
我对真正的细节感兴趣,比如它与尾盘、上行的使用,或者其他应该考虑的概念有什么不同。谢谢!
发布于 2021-02-15 08:39:09
next命令在内部有点像uplevel (特别是uplevel 1),因为它在运行超类实现时暂时删除调用next 的方法的堆栈帧,在next返回时恢复堆栈帧。
这意味着您可以重写超类中的方法,而不需要特别为此做准备的超类。对于Tcl来说,这是其他一些旧的对象系统的一个主要问题,您需要一个特殊的调用来获得upvar和uplevel的深度参数,而且很容易忘记这一点,所以我更改了TclOO。但是,这种更改的直接后果意味着您在S1 » addone中所做的操作将无法工作;它将在调用范围内创建/覆盖一个附加变量xx。S2 » addone是我认为是惯用的。
如果要在方法和它覆盖的方法之间传递一个内部变量(根据定义,这需要两者合作),则在对象的状态命名空间中使用一个变量;您的类对此有完全的控制。或者通过my或[self]调用一个方法;这是一个标准的方法调用(包含所有的含义)。
https://stackoverflow.com/questions/66201923
复制相似问题