如何在 TCL 中编写将使用全局字典或其他字典的过程

How to write a procedure in TCL that will use either a global dictionary or another one

提问人:iostrym 提问时间:10/10/2023 最后编辑:marc_siostrym 更新时间:11/3/2023 访问量:31

问:

我有一个使用全局词典的过程。这是一个全局性的,因为我需要该过程才能在字典中读取并更新它。

我需要能够使用这个全局词典或另一个词典,具体取决于该过程的参数。dict_glob1dict_glob2

我可以提供正确的词典作为参数,但恐怕我无法更新它。事实上,我想我只需要能够提供全局词典的“名称”。但是我不知道如何将字典的“名称”与程序中的真实字典联系起来。

TCL公司 全球

评论

1赞 Colin Macleod 10/10/2023
您需要 - tcl-lang.org/man/tcl/TclCmd/upvar.htmupvar

答:

3赞 Donal Fellows 10/10/2023 #1

最简单的方法是使用(加上解码参数所需的任何逻辑)在过程中为要访问/更新的变量提供一致的本地名称。这保持了设置呼叫附近的复杂性;之后的一切都很简单(或者至少像需要的那样复杂)。upvarupvar

这是一个人为的版本(只是一个局部变量名称,对于“字典”来说有点助记符):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 参数,以避免一些奇怪的参数分析。当你使用时,你几乎总是意味着......upvarupvarupvar 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"