Arrays 不覆盖数组的现有值的set函数

Arrays 不覆盖数组的现有值的set函数,arrays,tcl,Arrays,Tcl,我经常看到这样的全局变量构造: global var if {![info exists var]} { set var "Some default value" } 或对于阵列: global array if {![info exists array(key)]} { set array(key) "Some default value" } 写起来有点长。所以我写了一个非常基本的集合函数: proc set_if_not_exist { name value } {

我经常看到这样的全局变量构造:

global var
if {![info exists var]} {
    set var "Some default value"
}
或对于阵列:

global array
if {![info exists array(key)]} {
    set array(key) "Some default value"
}
写起来有点长。所以我写了一个非常基本的集合函数:

proc set_if_not_exist { name value } {
    if {![info exist $name ] } {
        set $name $value
    }
}
这很好,但当我尝试对数组执行同样的操作时,情况会变糟:

代码

#! /usr/bin/tclsh
proc my_set { name key value } {
    global $name
    if { ! [ info exist $name($key) ] } {
        set $name($key) $value
    }
}

global my_array

set my_array(a)  "a set value"

my_set my_array a "OK"
my_set my_array b "OK"

puts "a: $my_array(a)\n"
puts "b: $my_array(b)\n"
我想要的是:

a: a set value
b: OK
我得到了什么

can't read "name(a)": variable isn't array
    while executing
"info exist $name($key) "
    (procedure "my_set" line 4)
    invoked from within
"my_set my_array a  "OK""
因此:从函数内部设置数组的惯用语法是什么?

请尝试以下方法

proc my_set { name key value } {
    global $name
    if { ! [ info exist [set name]($key) ] } {
        set $name($key) $value
    }
}

我找到了我想要的方法:需要使用
upvar

proc my_set { name key value } {
    global $name
    upvar 1 $name arr
    if { ! [ info exist arr($key) ] } {
        set arr($key) $value
    }
}

你很接近你自己找到的答案。但如果您将过程编写为:

proc my_set {name value} {
    upvar 1 $name var
    if {![info exist var]} {
        set var $value
    }
}
然后,您可以简单地对常规变量和数组元素使用相同的过程,就像您习惯于使用set命令一样:

my_set my_array(a) "a set value"
my_set my_array(a) "OK"
my_set my_array(b) "OK"
然后
parray my_数组
给出:

my_array(a) = a set value
my_array(b) = OK

只有当从全局命名空间调用
my_set
过程时,
upvar 1
的解决方案才有效。当从另一个过程调用此过程时,它们将失败。正确而简单的解决方案是:

proc my_set { name key value } {
    upvar #0 $name arr
    if { ![info exist arr($key)] } {
        set arr($key) $value
    }
}

如果使用
upvar
访问其作用域中的数组,则不需要
global