Tcl 数组是否返回引用或值?

Tcl 数组是否返回引用或值?,tcl,Tcl,数组得到的返回的是什么,是引用还是值?我有一个数组,它将列表作为值,列表必须经常修改。做这件事的有效方法是什么?首先是一些基础知识。Tcl没有引用。一点也没有。所以tcl中的所有命令都会返回值 第一个问题的简单答案是它返回一个值 为了深入了解tcl的值语义是如何工作的,有两种方法来看待事物 首先,这是严格从语言规范中看到的语言。换句话说,用户/程序员的视角。从这个角度来看,tcl只能做一件事:处理字符串。tcl中的所有内容都是字符串。更严格地说,您可以说tcl具有非常强的值语义,几乎没有任何引用

数组得到的
返回的是什么,是引用还是值?我有一个数组,它将列表作为值,列表必须经常修改。做这件事的有效方法是什么?

首先是一些基础知识。Tcl没有引用。一点也没有。所以tcl中的所有命令都会返回值

第一个问题的简单答案是它返回一个值

为了深入了解tcl的值语义是如何工作的,有两种方法来看待事物

首先,这是严格从语言规范中看到的语言。换句话说,用户/程序员的视角。从这个角度来看,tcl只能做一件事:处理字符串。tcl中的所有内容都是字符串。更严格地说,您可以说tcl具有非常强的值语义,几乎没有任何引用语义(有点像C,只是C更喜欢数字(甚至字符串只是C中的数字数组))

如果是,列表是什么?从这个角度来看,列表只不过是特殊格式的字符串。如果字符串看起来像一个列表,那么它就是一个列表。如果不是,则是无效列表。无论哪种情况,它们都是字符串。数字也是如此

那么,什么是阵列呢?嗯,数组有点特殊。同样,文件是特殊的,url是特殊的。要获取文件的值(内容),可以使用诸如
open
read
gets
等命令。要获取数组的值,可以使用类似于
array get
的命令和特殊的
$array\u name(key)
语法。您可以将数组看作是一种内置的简单键值对数据库。它们的行为与tcl中的常规变量不同,因为
$array\u name
会产生语法错误,而不是数组值(内容)的字符串表示。但是
array get
允许将数组序列化回字符串表示形式,所以从everyting-is-a-string的角度来看,一切都很好

第二个观点是语言是如何实现的。在C级,tcl中的所有内容都是对象,变量/值始终作为指针传递。Tcl竭尽全力以尽可能快的访问和修改速度存储数据。因此,虽然从高级视图来看,列表只不过是一种字符串格式约定,但在低级实际上实现方式与字符串不同。这使tcl能够快速处理列表、数组和数字。但是,如果显式要求tcl将列表、数组或数字视为字符串,则tcl别无选择,只能将对象解析为字符串,然后将该字符串重新解析回本机对象类型。这就是所谓的闪烁,它会消耗大量的CPU周期

Tcl还实现了在后台写时修改。因此,返回列表或字符串的完整副本实际上不会导致在内存中创建另一个对象副本。只有尝试修改返回值时,才会创建副本

因此,第二个问题的答案是,如果您关心速度(regexp、stringfirst等),则避免使用字符串命令处理列表数组。使用列表命令处理列表,使用字符串命令处理字符串。有些情况下,你无法避免它,有些情况下,字符串命令可能更容易,速度并不重要,但一般来说,尽量避免闪烁。这是养成的好习惯

综上所述,修改列表的最有效方法是在数组上使用list命令(
lset
lrange
等)。例如,要修改数组“foo”中列表“bar”中的第二个元素,我们可以执行以下操作:

lset foo(bar) 1 "new value"

非常感谢您的深入解释。这将有助于比我多得多的人:)我写了一个这样的小脚本:
array set ma[list f“First”s[list”sec“ond”]]put ma(f)put ma(s)
当我运行它时,它会打印
ma(f)ma(s)
。我做错了什么,你能告诉我吗?严格来说,Tcl具有不可变的引用语义(保证没有引用循环)。从Tcl代码的角度来看,它看起来就像值语义,只是速度更快。
ma(s)
ma(f)
只是字符串。因此tcl正确地将它们视为字符串并将其打印出来(记住,不需要引用没有空格或特殊字符的字符串)。如果希望将单词(字符串)视为变量名,则需要向其添加
$
puts$ma(s)
,这与puts$ma(s)相同,因为无需引用裸字规则。或者,您也可以将字符串
ma(s)
传递给set命令以检索值:
puts[set ma(s)]