What is the benefit of Keyword Lists?

In elixir we have Maps:

> map = %{:a => "one", :b => "two"} # = %{a: "one", b: "two"}
> map.a                             # = "one"
> map[:a]                           # = "one"

We also have Keyword Lists:

> kl = [a: "one", b: "two"]       # = [a: "one", b: "two"]
> kl2 = [{:a, "one"},{:b, "two"}] # = [a: "one", b: "two"]
> kl == kl2                       # = true
> kl[:a]                          # = "one"
> kl.a                            # = ** (ArgumentError)

Why both?

Syntax? Is it because Keyword Lists have a more flexible syntax allowing them to be defined without curlys and even without brackets as the last param of a function call? Then why not give Maps this syntactic sugar?

Duplicate Keys? Is it because Keyword Lists can have duplicate keys? Why would you want both Map style access and duplicate keys?

Performance? Is it because Keyword Lists have better performance? Then why have Maps? And shouldn't maps be more performant at looking up members by key than a list of tuples?

JS Array and Ruby Hash like appearance? Is that it?

I understand that structurally they are different data representations. To me it seems that Keyword Lists in elixir serve to complicate the language through exceptional syntax (3 different syntactic variants), use case overlap with maps, and an unclear benefit.

What is the benefit of using Keyword Lists?

11077 次浏览
关键字列表 地图/结构 HashDect (已弃用)
重复的钥匙 yes 没有 没有
命令 是的 没有 没有
模式匹配 是的  yes 没有
表现1(插入) 非常快 fast³ 快4
Performance¹ (Access) slow⁵ 快速3 快4

关键字列表是轻量级的,下面有一个简单的结构,这使得它们非常灵活。您可以将它们看作是 Erlang 约定之上的语法糖,这使得与 Erlang 接口变得很容易,而不需要编写太难看的代码。例如,关键字列表用于表示函数参数,这是从 Erlang 继承的属性。在某些情况下,关键字列表是您唯一的选择,特别是如果您需要重复的键或排序。它们只是具有与其他替代品不同的属性,这使得它们更适合于某些情况,而不适合于其他情况。

映射(和结构)用于存储实际的有效负载数据,因为它们具有基于散列的实现。内部的关键字列表只是需要为每个操作遍历的列表,因此它们不具有常量时间访问等传统的关键字-值数据结构的属性。

长生不老药还引入了 HashDict作为 在它被写的时候,地图的性能很差的变通方案。然而,这是固定现在作为长生不老药1.0.5/Erlang 18.0和 HashDict 将在以后的版本中弃用

If you dig deeper into the Erlang standard library, there are even more data structures that store key/value pairs:

You also have these options when you need to store key/value pairs across multiple processes and/or VMs:


一般来说,当然是 看情况了TM。

2最好的情况是只是预先列表。

3适用于 Elixir 1.0.5及以上版本,在旧版本中可能会慢一些。

4 HashDict现在已被弃用。

5需要一个线性搜索,平均扫描一半的元素。

映射只允许特定键的一个条目,而 关键字列表允许重复关键字。地图是有效率的(特别是随着它们的成长) ,它们也可以是有效率的 用于长生不老药的模式匹配。

一般来说,对于命令行参数和传递选项之类的事情使用关键字列表,并在需要关联数组时使用 map (或另一种数据结构 Hashdect)。

关键字列表的主要好处是可以与现有的长生不老药和 erlang 代码库进行向下兼容。

如果用作函数参数,它们还添加了语法糖,类似于 Ruby 语法:

def some_fun(arg, opts \\ []), do: ...
some_fun arg, opt1: 1, opt2: 2

使用关键字列表的主要缺点是不可能对它们执行部分模式匹配:

iex(1)> m = %{a: 1, b: 2}
%{a: 1, b: 2}
iex(2)> %{a: a} = m
%{a: 1, b: 2}
iex(3)> a
1
iex(4)> k = [a: 1, b: 2]
[a: 1, b: 2]
iex(5)> [a: a] = k
** (MatchError) no match of right hand side value: [a: 1, b: 2]

让我们把它扩展到函数参数。假设我们需要处理一个基于一个选项的值的多子句函数:

def fun1(arg, opt1: opt1) when is_nil(opt1), do: do_special_thing
def fun1(arg, opts), do: do_regular_thing


def fun2(arg, %{opt1: opt1}) when is_nil(opt1), do: do_special_thing
def fun2(arg, opts), do: do_regular_thing

这将永远不会执行 do_special_thing:

fun1("arg", opt1: nil, opt2: "some value")
doing regular thing

With map arguments it will work:

fun2("arg", %{opt1: nil, opt2: "some value"})
doing special thing