列表是 Elixir 中一种基本的数据类型,用来保存一组值。列表是_不可变的_,也就是说无法修改。任何改变列表的操作都会返回一个新的列表。列表实现了 Enumerable 协议,因此可以使用 Enum 和 Stream 模块中的函数。
Elixir 中的列表实现为链表,而不是连续内存位置组成的数组。因此,访问列表中的元素所花的时间与列表的长度成线性关系。
列表可以用字面量形式、头尾表示法(使用cons运算符|)或两者的组合来写:
# Literal Form
[]
[1]
[1, 2, 3]
# Head-tail Notation
[]
# same as [1]
[1 | []]
# same as [1, 2, 3]
[1 | [2 | [3 | []]]]
# Mixed
# same as [1, 2, 3]
[1 | [2, 3]]
cons(|)运算符前面也可以有多个元素。
# Multiple prepends
[1, 2, 3 | [4, 5]]
可以用头尾表示法向列表追加元素。
list = [2, 1]
[3, 2, 1] == [3 | list]
# => true
在迭代过程中向列表追加元素被视为一种反模式。追加元素需要遍历整个列表,把元素添加到末尾;因此,如果在每次迭代中都追加一个新元素,就相当于每次迭代都要遍历一遍整个列表。
要把元素追加到列表末尾,可以先把它添加到反转后列表的开头,再把结果反转回来,这样能达到同样的效果。在开头添加是很快的操作,只需要常数时间。
# Appending to the end of a list (potentially slow)
[1, 2, 3] ++ [4] ++ [5] ++ [6]
# Prepend to the start of a list (faster, due to the nature of linked lists)
[6 | [5 | [4 | [3, 2, 1]]]]
# then reverse!
Kernel提供了几个常用于列表的函数:
hd/1返回列表的_头_,也就是列表中的_第一个_元素。tl/1返回列表的_尾_,也就是列表去掉_第一个_元素后剩下的部分。length/1返回列表中元素的数量。in/2返回一个布尔值,表示某个元素是否在列表中。此外还有List模块。
列表可以包含任意数据类型,也可以混合包含不同的数据类型。
list = [1, :a, 2.0, "string"]