关键字列表有什么好处?
What is the benefit of Keyword Lists?
在长生不老药中我们有地图:
> map = %{:a => "one", :b => "two"} # = %{a: "one", b: "two"}
> map.a # = "one"
> map[:a] # = "one"
我们还有关键字列表:
> 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)
为什么两者都有?
语法? 是因为关键字列表具有更灵活的语法,允许在定义它们时不使用大括号,甚至不使用方括号作为函数调用的最后一个参数吗?那为什么不给地图这个语法糖呢?
重复键?是因为关键字列表可以有重复键吗?为什么您需要地图样式访问和重复键?
性能?是因为关键字列表的性能更好吗?那为什么要有地图呢?在按键查找成员方面,映射不应该比元组列表更高效吗?
JS数组和Ruby哈希一样的外观?是吗?
我了解它们在结构上是不同的数据表示形式。在我看来,elixir 中的关键字列表似乎通过特殊的语法(3 种不同的语法变体)、用例与映射重叠以及不明确的好处使语言复杂化。
使用关键字列表有什么好处?
Keyword List
Map/Struct
HashDict (deprecated)
Duplicate keys
yes
no
no
Ordered
yes
no
no
Pattern matching
yes
yes
no
Performance¹ (Insert)
very fast²
fast³
fast⁴
Performance¹ (Access)
slow⁵
fast³
fast⁴
关键字列表是轻量级的,并且在它们下面有一个简单的结构,这使得它们非常灵活。您可以将它们视为 Erlang 约定之上的语法糖,使与 Erlang 的交互变得容易,而无需编写太难看的代码。例如,关键字列表用于表示函数参数,这是从 Erlang 继承的 属性。在某些情况下,关键字列表是您唯一的选择,尤其是当您需要重复键或排序时。它们只是具有与其他替代品不同的属性,这使得它们更适合某些情况而不太适合其他情况。
映射(和结构)用于存储实际有效负载数据,因为它们具有基于散列的实现。关键字列表内部只是每次操作需要遍历的列表,所以不具备常量访问等经典键值数据结构的特性。
Elixir 还引入了 HashDict
作为 poor performance of maps at the time it was written. However, this is fixed now as of Elixir 1.0.5/Erlang 18.0 and HashDict
will be deprecated in future versions.
的解决方法
如果你深入研究 Erlang 标准库,存储 key/value 对的数据结构甚至更多:
当您需要跨多个进程 and/or 虚拟机存储 key/value 对时,您也可以使用这些选项:
¹ 一般来说,当然 这取决于 ™。
² 最好的情况就是添加到列表中。
³ 适用于 Elixir 1.0.5 及更高版本,在旧版本中可能会更慢。
⁴ HashDict
现已弃用。
⁵ 需要线性搜索,平均扫描一半的元素。
地图只允许一个特定键的一个条目,而
关键字列表允许重复键。地图是高效的(尤其是随着它们的增长),并且它们可以
用于 Elixir 的模式匹配。
一般来说,使用关键字列表来处理命令行参数和传递选项等内容,并在需要关联数组时使用映射(或其他数据结构,HashDict)。
关键字列表的主要好处是向后兼容现有的 elixir 和 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
使用地图参数它将起作用:
fun2("arg", %{opt1: nil, opt2: "some value"})
doing special thing
在长生不老药中我们有地图:
> map = %{:a => "one", :b => "two"} # = %{a: "one", b: "two"}
> map.a # = "one"
> map[:a] # = "one"
我们还有关键字列表:
> 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)
为什么两者都有?
语法? 是因为关键字列表具有更灵活的语法,允许在定义它们时不使用大括号,甚至不使用方括号作为函数调用的最后一个参数吗?那为什么不给地图这个语法糖呢?
重复键?是因为关键字列表可以有重复键吗?为什么您需要地图样式访问和重复键?
性能?是因为关键字列表的性能更好吗?那为什么要有地图呢?在按键查找成员方面,映射不应该比元组列表更高效吗?
JS数组和Ruby哈希一样的外观?是吗?
我了解它们在结构上是不同的数据表示形式。在我看来,elixir 中的关键字列表似乎通过特殊的语法(3 种不同的语法变体)、用例与映射重叠以及不明确的好处使语言复杂化。
使用关键字列表有什么好处?
Keyword List | Map/Struct | HashDict (deprecated) | |
---|---|---|---|
Duplicate keys | yes | no | no |
Ordered | yes | no | no |
Pattern matching | yes | yes | no |
Performance¹ (Insert) | very fast² | fast³ | fast⁴ |
Performance¹ (Access) | slow⁵ | fast³ | fast⁴ |
关键字列表是轻量级的,并且在它们下面有一个简单的结构,这使得它们非常灵活。您可以将它们视为 Erlang 约定之上的语法糖,使与 Erlang 的交互变得容易,而无需编写太难看的代码。例如,关键字列表用于表示函数参数,这是从 Erlang 继承的 属性。在某些情况下,关键字列表是您唯一的选择,尤其是当您需要重复键或排序时。它们只是具有与其他替代品不同的属性,这使得它们更适合某些情况而不太适合其他情况。
映射(和结构)用于存储实际有效负载数据,因为它们具有基于散列的实现。关键字列表内部只是每次操作需要遍历的列表,所以不具备常量访问等经典键值数据结构的特性。
Elixir 还引入了 HashDict
作为 poor performance of maps at the time it was written. However, this is fixed now as of Elixir 1.0.5/Erlang 18.0 and HashDict
will be deprecated in future versions.
如果你深入研究 Erlang 标准库,存储 key/value 对的数据结构甚至更多:
当您需要跨多个进程 and/or 虚拟机存储 key/value 对时,您也可以使用这些选项:
¹ 一般来说,当然 这取决于 ™。
² 最好的情况就是添加到列表中。
³ 适用于 Elixir 1.0.5 及更高版本,在旧版本中可能会更慢。
⁴ HashDict
现已弃用。
⁵ 需要线性搜索,平均扫描一半的元素。
地图只允许一个特定键的一个条目,而 关键字列表允许重复键。地图是高效的(尤其是随着它们的增长),并且它们可以 用于 Elixir 的模式匹配。
一般来说,使用关键字列表来处理命令行参数和传递选项等内容,并在需要关联数组时使用映射(或其他数据结构,HashDict)。
关键字列表的主要好处是向后兼容现有的 elixir 和 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
使用地图参数它将起作用:
fun2("arg", %{opt1: nil, opt2: "some value"})
doing special thing