Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
upvar、TclOO和next—对(可能)意外行为的解释_Tcl - Fatal编程技术网

upvar、TclOO和next—对(可能)意外行为的解释

upvar、TclOO和next—对(可能)意外行为的解释,tcl,Tcl,我想知道是否有人可以解释为什么我可以在嵌套的过程中成功地链接upvars,但在嵌套的TclOO方法(那些在子类中重写的方法)中它不起作用。(有人告诉我,在TclOO类方法中调用[next]有点像“临时tailcall”,因为没有创建新的堆栈级别。是这样吗?如果是,完整情况如何?) 例如,以下三种方法的结果并不完全相同: proc addone {varname} { upvar $varname x; incr x; } proc addanotherone {varname} {

我想知道是否有人可以解释为什么我可以在嵌套的过程中成功地链接upvars,但在嵌套的TclOO方法(那些在子类中重写的方法)中它不起作用。(有人告诉我,在TclOO类方法中调用[next]有点像“临时tailcall”,因为没有创建新的堆栈级别。是这样吗?如果是,完整情况如何?)

例如,以下三种方法的结果并不完全相同:

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”的变量

如果不是,它实际上不是在同一个级别上运行,那么它更像是一个闭包吗

我感兴趣的是它与tailcall、uplevel的使用或任何其他应该考虑的概念的区别。
谢谢大家!

内部的
next
命令有点像
uplevel
(特别是
uplevel1
),因为它在运行超类实现时临时删除调用
next
的方法的堆栈帧,
next
返回时恢复堆栈帧(当然)

这意味着您可以覆盖来自超类的方法,而无需特别准备这些超类。这是Tcl的其他一些较旧对象系统的一个主要问题,在这些系统中,您需要一个特殊调用来获取
upvar
uplevel
的深度参数,而这一点很容易被忘记,所以,我为TrCro改变了一些东西。但是,这种改变的直接后果意味着你在<代码> S1·AdONo//C>中所做的工作是无效的;它在调用范围中创建/重写了一个额外的变量,<代码> XX >代码> < AdOnth>代码>是我认为的习惯用法。
如果要在方法和它所覆盖的方法之间传递内部变量(根据定义,这需要两者协作),请在对象的状态命名空间中使用变量;您的类可以完全控制该变量。或者通过
my
[self]
调用方法;这是标准方法调用(尽管如此).

我同意Donal所写的:让
addone
方法通过一个对象变量进行通信。调用堆栈移动总是容易中断,因为添加间歇混合等会改变调用堆栈级别,例如,在被调用方不知道的情况下。虽然构建示例是为了简洁地表达问题,但实际的World用例传递的是一个我希望就地修改的字典,而不是一个内部的东西。但是,我可能也误解了这种情况下的要点。因此,假设我希望通过一系列重载类传递dictvar的名称,以便就地修改,您会建议使用“临时暂存变量”保存dict varname,作用域为对象变量?(虽然目前我觉得不太清楚,但我将遵循Tcl中的最佳实践。)谢谢!这不值得再问一个问题吗?如果我理解正确:(a)您可以通过一系列
addone
调用将给定的Tcl字典作为方法参数传递,是的,但这是使用按值传递复制来完成的。(b)如果你想操纵一个单一的共享字典,那么使用一个保存字典的对象变量,然后从你的
addone
方法中访问它。请参阅本文中的
aDict
。注意分别使用
variable
my variable
。感谢Donal的回答和清晰。非常感谢感谢!