提问人:iostrym 提问时间:10/10/2023 最后编辑:marc_siostrym 更新时间:11/3/2023 访问量:31
如何在 TCL 中编写将使用全局字典或其他字典的过程
How to write a procedure in TCL that will use either a global dictionary or another one
问:
我有一个使用全局词典的过程。这是一个全局性的,因为我需要该过程才能在字典中读取并更新它。
我需要能够使用这个全局词典或另一个词典,具体取决于该过程的参数。dict_glob1
dict_glob2
我可以提供正确的词典作为参数,但恐怕我无法更新它。事实上,我想我只需要能够提供全局词典的“名称”。但是我不知道如何将字典的“名称”与程序中的真实字典联系起来。
答:
3赞
Donal Fellows
10/10/2023
#1
最简单的方法是使用(加上解码参数所需的任何逻辑)在过程中为要访问/更新的变量提供一致的本地名称。这保持了设置呼叫附近的复杂性;之后的一切都很简单(或者至少像需要的那样复杂)。upvar
upvar
这是一个人为的版本(只是一个局部变量名称,对于“字典”来说有点助记符):d
proc doTheThing {{argument "foo"}} {
if {$argument eq "foo"} {
upvar "#0" dict_glob1 d
} else {
upvar 1 dict_glob2 d
}
dict set d abc 123
}
调用方始终将变量名称作为参数传递更为正常。如果他们愿意,他们可以命名全局变量。在这种情况下,你会得到:
proc doTheThing {{varName "::dict_glob1"}} {
upvar 1 $varName d
dict set d abc 123
}
在本例中,我们将全局变量命名为默认参数,但调用方可以将其覆盖为他们希望的任何其他名称(命名空间或在其作用域中)。
评论
0赞
Donal Fellows
10/10/2023
建议(但不是必需)始终提供 level 参数,以避免一些奇怪的参数分析。当你使用时,你几乎总是意味着......upvar
upvar
upvar 1
0赞
iostrym
10/10/2023
谢谢,但可以肯定的是。如果我修改本地词典“d”,它会修改发出“d”的全局词典“dict_glob1”吗?
0赞
Donal Fellows
10/10/2023
这两个变量在所有有用的方面都是“相同的”。在内部,局部变量实现成为指向全局变量实现的指针;一旦建立链接,它就会非常非常快。
0赞
Cyan Ogilvie
10/10/2023
#2
Donal的回答当然是正确和全面的股票Tcl。我在这里添加一个注释,如果您(或未来的读者)正在使用 parse_args 提供的扩展参数处理,那么这种情况有一个参数属性:-alias
set dict_glob1 {name glob1}
set dict_glob2 {name glob2}
proc doTheThing args {
parse_args $args {
-use {-alias}
-fooval {-required}
}
dict set use foo $fooval
}
doTheThing -fooval first -use dict_glob1
doTheThing -use dict_glob2 -fooval second
puts "dict_glob1: $dict_glob1" ;# prints "name glob1 foo first"
puts "dict_glob2: $dict_glob2" ;# prints "name glob2 foo second"
与直接示例相同,传递给参数的名称可以是完全命名空间限定的名称,以直接引用全局变量,而不是调用方帧中的该名称。upvar
-alias
如果此示例中未提供该选项,则不会建立任何链接:-use
dotheThing -fooval third ;# Not an error, but doesn't affect any variables here
可以使用 argument 属性将其设置为必需选项:-required
proc doTheThing args {
parse_args $args {
-use {-alias -required}
-fooval {-required}
}
dict set use foo $fooval
}
doTheThing -fooval forth ;# Now it's an error: "option -use is required"
评论
upvar