我正在使用嵌套字典(openDocuments)并尝试更新级别
dict set openDocuments $docId D_itemAt {1 {} 2 {} 0 {} e {}}
,其中 D_itemAt
下的四个键 (1,2,0,e) 是以下过程的两个版本中使用的 D_itemType
。请原谅我丑陋的测试代码。
我的问题是,在第一个版本中为每个
D_itemType
分配新字典和在第二个版本中使用dict with
更新键的值有区别吗?
我的意思是内存使用/周转方面的差异。例如,
dict with
是否只是更新键的内存位置中保存的值,从而不会导致垃圾回收?将每个 D_itemType
设置为新字典会导致旧字典的垃圾回收吗?
也许这不是很重要,但是这个过程在撰写文档时会被执行很多很多次,我想知道是否一个版本会导致 Tcl 在后台的“工作”比另一个版本少。
感谢您考虑我的问题。
proc UpdateOpenDocsItemAt { data } {
upvar 1 openDocuments openDocuments
upvar 1 docId docId
foreach {\
D_itemType\
D_dataKey\
D_prevKey\
D_nextKey\
D_bufferId\
D_charStart\
D_charLength\
D_charBegin } $data {
dict set openDocuments $docId D_itemAt $D_itemType\
[list D_dataKey $D_dataKey\
D_prevKey $D_prevKey\
D_nextKey $D_nextKey\
D_bufferId $D_bufferId\
D_charStart $D_charStart\
D_charLength $D_charLength\
D_charBegin $D_charBegin]
}
}
proc UpdateOpenDocsItemAt { data } {
upvar 1 openDocuments openDocuments
upvar 1 docId docId
foreach {\
itemType\
dataKey\
prevKey\
nextKey\
bufferId\
charStart\
charLength\
charBegin } $data {
dict with openDocuments $docId D_itemAt $itemType {
chan puts stdout "$itemType $dataKey $prevKey $nextKey $bufferId $charStart $charLength $charBegin"
set D_dataKey $dataKey
set D_prevKey $prevKey
set D_nextKey $nextKey
set D_bufferId $bufferId
set D_charStart $charStart
set D_charLength $charLength
set D_charBegin $charBegin
}
}
}
dict with
和 dict update
命令可让您制作自己的字典操纵器。它们使执行诸如将字符插入键值的中间或增加键内键的值等操作变得更容易。(创建它们是因为我们在语法上无法拥有深入内部的复合键,并非没有以与字典的设计目标相反的方式限制键的空间。)
从概念上讲,
dict with
(具有非空主体)就像一个dict get
,提取,eval
,重新包装(就像使用dict create
或可能是dict put
),然后是dict set
。对外部按键序列的管理和按键组的继承进行了一些小的优化,但它实际上并不是超级智能。特别是,提取阶段不是很聪明,因为它无法知道内部字典中的键到底是什么;作为脚本作者,you应该知道这一点,但编译器不知道。不使用任何痕迹;写回恰好发生在主体评估结束时。
这样做的结果是,放入变量中的值的引用计数将大于 1(因为至少有一个来自字典的引用和一个来自局部变量的单独引用),因此不符合就地更新。
就您而言,因为您只写入内部字典,所以您最好不要使用
dict with
。当您思考“我需要从内部读取,以复杂/自定义的方式摆弄事物,然后写回”时,请使用 dict with
。或者使用带有空主体的版本从内部字典中执行简单的读入变量;作为一种优化,我们在这种情况下跳过写回。