列表是Elixir中重要的数据结构。相信其他编程语言中也有类似列表的结构。Lisp的命名来自对列表的处理。在C,Java语言中,列表类似数组结构。Elixir的列表远比数组强大,它更像高级语言python的列表。
列表的定义
Elixir中使用方括号[]
定义一个列表,列表的元素可以是任意Elixir类型,列表可以没有元素,即空表,也可以是任意多个元素。列表还可以去嵌套。
iex(1)> l = []
[]
iex(2)> is_list l
true
iex(3)> l1 = [1, 2, :hello, "word", [1, 3]]
[1, 2, :hello, "word", [1, 3]]
iex(4)>
head和tail
Elixir列表是一个的存储结构是链表。也就是说,当你访问列表的第一个元素的时候,速度会很快。但是要访问其中的某个元素,将会带来比较大的开销。因为访问n个元素的时候,必须先遍历n-1个元素。
因此,由于列表的第一个元素比较特殊,访问数独快嘛。就单独给了它一个名字,列表头(head),除了head之外,剩下的元素即位列表尾(tail)。只有一个元素的列表head就是那个元素,tail为空,空列表的没有head和tail。Elixir提供了两个内置函数hd和tl分别访问列表的head和tail。
iex(1)> l = [1, 2, 3, 4]
[1, 2, 3, 4]
iex(2)> hd l
1
iex(3)> tl l
[2, 3, 4]
iex(4)> hd []
** (ArgumentError) argument error
:erlang.hd([])
iex(5)> tl []
** (ArgumentError) argument error
:erlang.tl([])
iex(6)> hd [:sigle_element]
:sigle_element
iex(7)> tl [:sigle_element]
[]
|
操作符
列表的head和tail十分重要。Elixir提供了一个操作符用于把head和tail连接起来。
iex(1)> head = 1
1
iex(2)> tail = [2, 3, 4]
[2, 3, 4]
iex(3)> [head | tail]
[1, 2, 3, 4]
iex(4)>
实际上,列表就是使用|
递归定义的,之前我们写的[]加元素,其实是列表定义的一个语法糖。
iex(1)> [1, 2, 3]
[1, 2, 3]
iex(2)> [3|[]]
[3]
iex(3)> [1|[2|[3|[]]]]
[1, 2, 3]
模式匹配
函数式语言最重要的是一个特性就是模式匹配。Elixir的列表也可以进行模式匹配。|
既然可以连接列表的head和tail,实际上也是把列表分为head和tail。那么就可以使用模式匹配。这个技术很强大,尤其是在函数递归调用的时候。
iex(1)> l = [1, 2, 3, 4]
[1, 2, 3, 4]
iex(2)> [head|tail] = l
[1, 2, 3, 4]
iex(3)> head
1
iex(4)> tail
[2, 3, 4]
列表的操作符
列表可以通过++
符号连接两个列表,也可以通过--
把列表进行相减。in
判断是否属于成员。
iex> [ 1, 2, 3 ] ++ [ 4, 5, 6 ]
[1, 2, 3, 4, 5, 6]
iex> [1, 2, 3, 4] -- [2, 4]
[1, 3]
iex> 1 in [1,2,3,4]
true
iex> "wombat" in [1, 2, 3, 4]
false
列表还是元组
看起来|
和++
都可以连接列表,但是在某些应用场景还是有区别的:
iex(1)> l = [1, 2, 3]
[1, 2, 3]
iex(2)> [0] ++ l
[0, 1, 2, 3]
iex(3)> [0|l]
[0, 1, 2, 3]
iex(4)> l ++ [4]
[1, 2, 3, 4]
我们知道,列表是链表,访问第一个元素很快,可是访问列表中其他的元素会很慢。所以使用++
的时候在末尾追加列表会很慢。需要访问链表的最后一个元素,这就重建了原先的列表,让原先列表的末尾元素指向那个新元素。
还记得元组么,元组的数据结构是顺序的线性表,元组在内存中是连续存储的。因此可以通过元素的下标访问元组的元素,并且这样的操作速度很快,但是元组在修改或添加元素时开销很大,因为这些操作会在内存中对元组的进行整体复制。
因此,选择列表还是元组,本质上是对顺序线性表和线性链表的选择。
函数式语言
本节只是对列表进行简单的介绍。我们不止一次说过列表的强大,模式匹配配合列表将会是Elixir强大的表现力。此外,我们在介绍字典类型结构的是时候,将会介绍键值列表。一种有键值对的列表。在介绍模块,尤其是Enum模块提供了对列表的操作。
到目前为止,我们希望函数式语言带来不同的编程思想,Think Different。通过对前面的学习介绍,可以对Elixir和函数式编程语言有了比较感性的感觉。可是除了语言的表达操作上与常见的编程语言有所不同,但也没有太大的不同。为了解决这个疑惑,我们将会在下一节介绍所谓的函数式语言。