关于下面的代码,我有两个问题。
当通道事件调用
ReadLine中使用upvar?在upvar的实验中,我使用了这个完全相同的场景,但ReadLine是直接而不是通过事件调用的;而且它运行得很好。它失败了,因为state($sock)是不被识别的。是否需要一个不同的#n值,还是必须是全局的?它尝试了#2,这引发了一个错误,这是一个坏值。ReadLine I试图创建指向$state($sock)的指针,使其指向列表本身。例如,在实验中,lappend $sptr $op运行得很好,但是在set row [lindex $sptr 0]上失败了,因为$sptr是state(1)。但是,如果使用set (如set row [lindex [set $sptr] 0] ),则确实有效。为什么会这样呢?是否有另一种方法来获取指针所指向的值?试图在Tcl中使用指针是个坏主意吗?将过程体转换为字节码表示的事实是否意味着使用指针没有多大区别?谢谢。
proc ClientConnect {sock client_ip client_port} {
if {![info exists state($sock)]} {set state($sock) {1}};
chan configure $sock -buffering line -blocking 0 -translation crlf
chan event $sock readable [list ReadLine $sock]
}
proc ReadLine {sock} {
# The #1 in upvar is to first caller, which is ClientConnect.
# Make a ptr to the array list rather than retrieving it each reference,
# such that $sptr is state($sock)'s list.
upvar #1 state r
set sptr r($sock)
puts stdout "x: [lindex $r($sock) 0]"; #Fails to recognize state.
set row [lindex [set $sptr] 0]
}似乎工作正常的实验代码:
proc ReadLine {sock} {
upvar #1 row rtemp; #Recognizes row.
set r rtemp($sock)
lappend $r "new"
set line "Content-length: 247899"
if { [string first "Content-length:" $line] == 0 } { lappend $r [string trim [string range $line 16 end]] }
lappend $r "help"
puts [lindex [set $r] 3]; #Output is: 247899.
puts $rtemp($sock); #Output is: 1 GET new 247899 help.
}
proc do {sock} {
set row($sock) {1 GET}
ReadLine $sock
}
set sock 1
do $sock发布于 2021-07-26 14:21:39
如果需要,可以使用upvar,但是您会发现回调上面唯一可见的堆栈帧是全局堆栈框架。就好像它是用uplevel #0调用的。它看不到内部过程,如果您稍微考虑一下,原因是显而易见的:当调用发生时,不能保证堆栈上有任何特定的过程。
如果需要将状态从安装回调的位置传递到调用回调的位置,最简单的方法是使用协同(可以从实际的全局回调恢复)或使用TclOO对象(当然,可以封装各种复杂的状态)。在8.5和之前的版本中,您受到了更多的限制,必须使用全局/命名空间变量,这可能会变得更加混乱。
若要使变量访问正常工作,请使用upvar为变量创建别名:
# upvar 0 is special in that it aliases a currently-visible variable
upvar 0 row($sock) r
puts [lindex $r 0]唯一真正的限制是不能在数组中放置数组。它在很久以前就被删除了,因为它很难使用,而且容易导致崩溃。
https://stackoverflow.com/questions/68524444
复制相似问题