在erlang中,字符串是整数列表。因为它们是整数,所以它们可以存储任何unicode字符。
当想要连接2个字符串时,可以使用 如下string:concat/2
实现:
lib/stdlib/src/string.erl
1 | %% concat(String1, String2) |
另一种++
操作是一个BIF,在C中实现的内置函数 erts/emulator/beam/erl_bif_lists.c
1 | /* |
首先,A
计算长度。此操作是O(n)
这里n
是列表的长度(erts/emulator/beam/utils.c
)。如果任一列表为空,则返回另一个列表。
在进程堆上为新列表分配空间。每个列表项的大小为2 Eterm
:列表本身为1,元素为1。最后只是复制A
到新分配的列表并在其尾部添加B。
对于last = CONS(hp, CAR(list_val(list)), make_list(hp+2)),
定义在: erts/emulator/beam/erl_term.h。
1 | #define CONS(hp,car,cdr)\ |
make_list
用于Eterm
从进程堆上的指针返回标记为列表的列表。list_val
相反并返回列表堆上的地址。CONS
将2个元素放入hp[0]
(列表中的元素)和hp[1]
(下一个列表项)并返回列表hp
作为Eterm。
这个复杂的表达现在可以解读为:
hp[0]
要复制的列表的元素中Eterm
在stack(hp+2
)上将下一个列表项设置为以下内容列表A
完全复制后,最后一个元素设置为B即
CDR(list_val(last)) = B。
一个通常字符有4个字节的大小。 erts/emulator/beam/sys.hEterm。
小整数可以直接存储在这4个字节中。有26位可用于存储一个小整数,因此可以存储多达2²⁵= 33554432。我们可以认为unicode字符可以直接存储在列表中。 如果一个字符串有n
字符,它将使用 2 * n
单词。binary
相反的A 将使用3到6个字(取决于数据大小)加上数据本身的大小。存储为列表的字符串大约占存储为a的空间的8倍binary
。
对于其他的, 不会复制指向的值,只会复制列表项。 将n
元组记录列表附加到元组列表m
将花费相同的时间/内存,如将长度字符串连接n
到一个长度字符串 m
。 唯一的区别是元组没有封装 Eterm
。该列表仅包含 Eterm
一个_指向_元组的_指针_:它存储在堆中的位置。
对于有!发生消息时,应该使用 binary
和IoList
尽可能。IoList为iolist = [char() binary() iolist()]
。