tcl dict:列表值是参数?

tcl dict: list values are arguments?

我以前从未使用过 Tcl 的 dict。虽然界面看起来很容易使用,但我对它的设计感到非常惊讶,并且不知道它在内部是如何工作的。有人可以启发我吗?我可能遗漏了一些基本的东西。

我熟悉 C 级别的 Tcl 内部散列 tables。所有操作都引用 Tcl_HashTable 变量。对于 dict 我还期望在更新或查阅字典时涉及 C 级别的内部变量。因此,我会理解是否使用 Tcl 级别的字典名称来引用内部哈希变量。但是,dict create returns 一个列表,而 dict get 接收一个列表作为值参数。因此,列表不是字典名称,而是作为值传递。

这也提出了一个问题:内部散列 table 是在哪个点构建或更新的?在 https://wiki.tcl-lang.org/page/dict 我读到“字典和列表的内部表示之间的转换是无损的”。这更令人困惑:为什么列表要实现为散列 table?

(还有一个附带问题:对于允许作为键和值的内容是否有任何限制?至少使用格式正确的列表似乎是可行的。)

谢谢!

在内部,Tcl 的字典是一种特殊的 Tcl_HashTable,它得到了增强,因此保留了键的插入顺序。 (散列 table 条目额外保存在双向链表中,代价是每个条目额外存储两个指针。)它们还使用任意 Tcl_Obj 值作为键和值;这些值根本不会被解释(除了在整个字典被序列化的情况下被序列化为字符串)并且键将始终具有用于哈希目的的标准 UTF-8 表示计算,但除此之外绝对可以是任何值。 (是的,这包括二进制数据、列表、其他字典、任何东西。)唯一的例外是你不能将字典放入自身,直接或间接;尝试这样做的行为将使容器发生变化,使其成为容器的修改副本。 (这是 Tcl 如何管理其复制(共享)写入值语义的结果。)

dict 的标准序列化是通过遍历条目序列并依次为每个键和值发出带引号的元素来完成的。这是使用用于序列化列表的相同引擎完成的。解析字符串以获取字典也与列表共享底层的基本字符串解析器。这种共享的结果是所有具有偶数个元素的列表都可以解释为字典,但这样做可能会删除重复元素;如果索引中与键对应的元素都是唯一的,则从列表到字典再返回列表的转换在元素方面是无损的(对于规范形式的列表,绝对无损)。 dict→list→dict 往返也是无损的(包括以规范形式开始时的绝对)。由于这种高度的兼容性,在类型转换代码中 另外 有额外的代码来识别何时从列表中创建字典并跳过实际构建字符串;直接处理元素。 反之亦然, 将字典转为列表也将跳过代价高昂的字符串生成。 这是安全的,因为我们知道这两种类型对基本元素的解析是相同的,但这是基本设计的一部分。

底层散列 table 是 Dict 结构的主要部分,它作为字典的内部表示。有一个多层引用管理系统,就像在相应的 List 结构中一样,但除非您深入了解 Tcl 的内部结构,否则您真的不需要关心它。


dict create 确实 return 一本字典。

% set d [dict create a b c d]
a b c d
% tcl::unsupported::representation $d
value is a dict with a refcount of 4, object pointer at 0x7faf35825c00, internal representation 0x7faf3503d910:0x0, string representation "a b c d"
% tcl::unsupported::disassemble script {set d [dict create a b c d]}
ByteCode 0x0x7faf36053c10, refCt 1, epoch 17, interp 0x0x7faf36019010 (epoch 17)
  Source "set d [dict create a b c d]"
  Cmds 2, src 27, inst 8, litObjs 2, aux 0, stkDepth 3, code/src 0.00
  Commands 2:
      1: pc 0-6, src 0-26        2: pc 2-5, src 7-25
  Command 1: "set d [dict create a b c d]"
    (0) push1 0     # "d"
  Command 2: "dict create a b c d..."
    (2) push1 1     # "a b c d"
    (4) dup 
    (5) verifyDict 
    (6) storeStk 
    (7) done 

( dup/verifyDict 被用来强制文字的字典性。编译器已经知道它是一个字典,但它强制类型是因为表示敏感代码— 虽然 强烈 气馁 — 肯定存在于野外。)