在tcl中创建和附加现有数组

时间:2013-07-02 19:48:21

标签: arrays tcl

大家好我需要一些关于tcl数组的帮助。我在tcl中有两个程序,如下所示:

    proc A {} {
      set lst_A [list];
      if {true} {
        lappend lst_A [::B $file1];
      } else {
        foreach id $allId {
          lappend lst_A [::B $id];
        }
      }
      return $lst_A;
    }

    proc B {fileID} {
      set fileName [::getFileName $fileID];  # getFileName returns filename from fileid
      set tcName "[set ItemName]_[set ItemId]";
      array set tcArrayName {$fileName $tcSpec};
      return $tcArrayName;
    }

现在我想创建一个数组,它将是一个键值对,其中key是某种文件id,value是与该id相关联的名称。现在问题是在proc A中,如果条件为真,我想创建只有一个键值对的数组,然后将该数组附加到lst_A,在这种情况下,它只包含一个项,即返回的数组。但是如果条件是假的,那么我遍历一些id并且对于每个id,我调用proc B并创建数组,然后将其附加到lst_A,在这种情况下,它将包含多个键值配对数组。

所以我在tcl教程中阅读了有关数组的内容之后编写了上面两个程序并创建了数组。但不确定这是正确的方式还是最优化的方式。

我的最终目标是创建一个lst_A或者我会说应该是一个数组,如果条件为真,它将只包含一个键值对,否则将是一个具有多个键值对的数组。由于我在proc B中创建数组,我只能想到将proc B中的键值对作为数组返回,然后将该数组附加到列表中,即proc A中的lst_A。

任何建议???

1 个答案:

答案 0 :(得分:5)

您在这里将列表与列表混淆。

在tcl中,您无法将数组传递到函数中或从函数返回它们。此外,tcl使用术语"数组"用于C ++调用"映射"或者Perl和Ruby调用"哈希"或Javascript调用"对象"。该术语来自这样的事实,即所有这些事物通常被称为"关联数组"在计算机科学。所以"阵列"在tcl中是键值对,而不是数据序列。

阵列通常不会退化为价值观(或经验丰富的tcl程序员会称之为"字符串")。因此:

array set tcArrayName {$fileName $tcSpec};
return $tcArrayName;

生成语法错误:

can't read "tcArrayName": variable is array

您实际上可以将数组的内容简化为可以返回的值。但您必须通过[array get]命令手动执行此操作:

return [array get tcArrayName]

上面的命令将以两元素列表的形式返回tcArrayName数组的内容:

"$fileName $tcSpec"

也恰好是一个字符串。这就是实际的字符串:字符' $'其次是字符',' i'' l',' e',' N',& #39; a',' m',' e'不是文件名和连接的项目名称和项目ID。文字字符串" $ fileName $ tcSpec"。

那是因为你在这行代码中使用了{}分组:

array set tcArrayName {$fileName $tcSpec}

在tcl中,{xxx}的行为与'xxx'在Perl中的行为方式相同。基本上它是一个不被替换的文字字符串。如果您想要tcl进行$替换,那么您需要使用""分组:

array set tcArrayName "$fileName $tcSpec"

但这很脆弱,因为如果fileName包含空格,那么它会破坏代码。更有效的方法是:

array set tcArrayName [list $fileName $tcSpec]

但在这种情况下使用array有点多余,因为您所做的只是使用键值列表(在更现代版本的更新版本中称为dict)进行初始化tcl.BTW,您使用的是什么版本的tcl?)然后立即将其丢弃并将其内容作为键值列表返回。

为什么不简单地返回该键值列表:

proc B {fileID} {
  set fileName [::getFileName $fileID];  # getFileName returns filename from fileid
  set tcName "[set ItemName]_[set ItemId]"
  return [list $fileName $tcSpec]
}

但我们仍然不清楚。如果您尝试执行B,则会看到此错误:

can't read "ItemName": no such variable

这是因为tcl默认情况下不会将全局变量导入函数。因此,ItemName中不存在变量ItemIdB。您需要通过global命令显式导入它:

proc B {fileID} {
  global ItemName
  global ItemId

  # ...
}

或使用完全限定的变量名称通过全局命名空间访问它:

set tcName "[set ::ItemName]_[set ::ItemId]"

所以B应如下所示:

proc B {fileID} {
  set fileName [::getFileName $fileID];  # getFileName returns filename from fileid
  set tcName "[set ::ItemName]_[set ::ItemId]"
  return [list $fileName $tcSpec]
}

B照顾Acan't read "file1": no such variable 也有问题:

file1

我们需要稍微修改一下才能访问变量proc A {} { set lst_A [list]; if {true} { ;# assuming that there will be a valid condition here lappend lst_A [::B $::file1]; } else { foreach id $allId { lappend lst_A [::B $id]; } } return $lst_A; }

dicts

这应该可以按预期工作。

如果你想在使用键值列表时加快一点,那么你应该真正阅读A。因此,dicts不会影响上面给出的代码,但它会影响调用lappend的代码。如果您打算使用dicts,则可以使用dict append替换上面的{{1}}来电。但旧版本的tcl没有明确的说法。