Progarmming Elixir Note
来自Dennis的知识库
2015年10月25日 (日) 12:31Dennis zhuang(讨论 | 贡献)的版本
目录 |
Dictionaries
- 一个项对应多个同个 key: Keyword 模块
- 要求顺序: Keyword 模块
- 使用模式匹配内容:Map
- 需要保存很多项:HashDict,Map 性能较差。
Keyword 模块示例
iex(21)> kw_list = [name: "Dave", likes: "Elixir", likes: "Ruby", where: "Beijing"] [name: "Dave", likes: "Elixir", likes: "Ruby", where: "Beijing"] iex(22)> kw_list[:likes] "Elixir" iex(23)> Dict.get(kw_list, :likes) "Elixir" iex(24)> Keyword.get(kw_list, :likes) "Elixir" iex(25)> Keyword.get_values(kw_list, :likes) ["Elixir", "Ruby"] iex(26)> Keyword.get_values(kw_list, :likes) ["Elixir", "Ruby"] iex(27)>
get_values 用来获取多个相同 key 的值。
Map
- 对于已经存在的 key,可以用 | 来更新,但是无法添加新 key:
iex(35)> person = %{name: "dennis", height: 1.7} %{height: 1.7, name: "dennis"} iex(36)> %{person | name: "green"} %{height: 1.7, name: "green"} iex(37)> %{person | age: 32} ** (KeyError) key :age not found in: %{height: 1.7, name: "dennis"} (stdlib) :maps.update(:age, 32, %{height: 1.7, name: "dennis"}) (stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5 (stdlib) lists.erl:1262: :lists.foldl/3
必须用 Dict.put_new/3 来添加新 key:
iex(37)> Dict.put_new(person, :age, 3) %{age: 3, height: 1.7, name: "dennis"}
Structs
其实就是固定 key 的 Map,但是却没有 Dict 和 Access 访问协议,并且只能定义在 module。在后续的 protocol 多态中扮演重要角色。
Structs 当然可以嵌套。 Structs 已经无法继承 @derive Access 协议,elixir 1.1 版本废弃了 Access 协议。Struct 本质上是 Map,可以使用模式匹配、Map 模块 API 等:
defmodule Subscriber do defstruct name: "", paid: false, over_18: true end iex(55)> s1 = %Subscriber{name: "dennis"} %Subscriber{name: "dennis", over_18: true, paid: false} iex(56)> %{s1 | name: "Green"} %Subscriber{name: "Green", over_18: true, paid: false} iex(57)> Map.get(s1, :name) "dennis" iex(58)> Map.put(s1, :name, "green") %Subscriber{name: "green", over_18: true, paid: false}
嵌套 struct,可以使用 put_in, update_in 来修改:
defmodule Customer do defstruct name: "", company: "" end defmodule BugReport do defstruct owner: %{}, details: "", severity: 1 end iex(77)> report = %BugReport{details: "test", owner: %Customer{name: "dennis", company: "leancloud"}} %BugReport{details: "test", owner: %Customer{company: "leancloud", name: "dennis"}, severity: 1} iex(78)> report %BugReport{details: "test", owner: %Customer{company: "leancloud", name: "dennis"}, severity: 1} iex(79)> report.owner.name "dennis" iex(80)> report.owner.company "leancloud" iex(81)> put_in(report.owner.name, "green") %BugReport{details: "test", owner: %Customer{company: "leancloud", name: "green"}, severity: 1} iex(82)> update_in(report.owner.name, &("Mr." <> &1)) %BugReport{details: "test", owner: %Customer{company: "leancloud", name: "Mr.dennis"}, severity: 1} iex(83)>
- 嵌套访问 Map 或者 Keyword list
也可以用 put_in, update_in, get_and_update_in 等。
iex(84)> report = %{details: "test", owner: %{company: "leancloud", name: "dennis"}, severity: 1} ...(84)> %{details: "test", owner: %{company: "leancloud", name: "dennis"}, severity: 1} iex(85)> put_in(report[:owner][:name], "green") %{details: "test", owner: %{company: "leancloud", name: "green"}, severity: 1}
但是上面见到的这些 put_in, update_in 都是宏,因此只能静态地传入固定的 key 列表,无法作为函数调用动态传入,也无法任意的 key 个数。因此他们还有函数的重载版本,增加一个 keys 列表:
iex(87)> update_in(report,[:owner,:name], &("Mr. " <> &1)) %{details: "test", owner: %{company: "leancloud", name: "Mr. dennis"}, severity: 1}
P.S. 其实这些都是类似 clojure 了。