设置函数,不会覆盖数组

时间:2019-08-06 08:32:36

标签: 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"
}

写的时间有点长。所以我写了一个非常基本的set函数:

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""

因此:从函数内部设置数组的惯用语法是什么?

4 个答案:

答案 0 :(得分:2)

您很接近找到自己的答案。但是,如果您将proc编写为:

proc my_set {name value} {
    upvar 1 $name var
    if {![info exist var]} {
        set var $value
    }
}

然后,您可以简单地对正则变量和数组元素使用相同的proc,就像您习惯使用set命令一样:

my_set my_array(a) "a set value"
my_set my_array(a) "OK"
my_set my_array(b) "OK"

然后parray my_array给出:

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

答案 1 :(得分:0)

尝试如下。

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

答案 2 :(得分:0)

我找到了实现自己想要的方式:需要使用upvar

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

答案 3 :(得分:0)

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

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