當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Elixir Kernel.SpecialForms.for用法及代碼示例


Elixir語言中 Kernel.SpecialForms.for 相關用法介紹如下。

用法:

for(args)
(宏)

理解允許您從可枚舉或位串快速構建數據結構。

讓我們從一個例子開始:

iex> for n <- [1, 2, 3, 4], do: n * 2
[2, 4, 6, 8]

推導式接受許多生成器和過濾器。可枚舉生成器使用 <- 定義:

# A list generator:
iex> for n <- [1, 2, 3, 4], do: n * 2
[2, 4, 6, 8]

# A comprehension with two generators
iex> for x <- [1, 2], y <- [2, 3], do: x * y
[2, 3, 4, 6]

也可以給出過濾器:

# A comprehension with a generator and a filter
iex> for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n
[2, 4, 6]

生成器也可用於過濾,因為它會刪除與 <- 左側的模式不匹配的任何值:

iex> users = [user: "john", admin: "meg", guest: "barbara"]
iex> for {type, name} when type != :guest <- users do
...>   String.upcase(name)
...> end
["JOHN", "MEG"]

位串生成器也受支持,並且在您需要組織位串流時非常有用:

iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]

理解內的變量賦值,無論是在生成器、過濾器還是塊內,都不會反映在理解之外。

:into:uniq 選項

在上麵的示例中,推導式返回的結果始終是一個列表。返回的結果可以通過傳遞 :into 選項來配置,隻要它實現 Collectable 協議,它就可以接受任何結構。

例如,我們可以使用帶有:into 選項的位串生成器來輕鬆刪除字符串中的所有空格:

iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"

IO 模塊提供流,它們都是 Enumerable Collectable ,這是一個使用理解的大寫回顯服務器:

for line <- IO.stream(), into: IO.stream() do
  String.upcase(line)
end

類似地,uniq: true 也可以用於理解,以保證隻有在之前沒有返回結果的情況下才會將結果添加到集合中。例如:

iex> for x <- [1, 1, 2, 3], uniq: true, do: x * 2
[2, 4, 6]

iex> for <<x <- "abcabc">>, uniq: true, into: "", do: <<x - 32>>
"ABC"

:reduce 選項

雖然:into 選項允許我們自定義對給定數據類型的理解行為,例如將所有值放入映射或二進製文件中,但這並不總是足夠的。

例如,假設您有一個帶有字母的二進製文件,您想計算每個小寫字母出現的次數,忽略所有大寫字母。例如,對於字符串 "AbCabCABc" ,我們要返回映射 %{"a" => 1, "b" => 2, "c" => 1}

如果我們要使用 :into ,我們需要一個數據類型來計算它所擁有的每個元素的頻率。雖然 Elixir 中沒有這樣的數據類型,但您可以自己實現一個。

一個更簡單的選擇是對字母的映射和過濾使用理解,然後我們調用 Enum.reduce/3 來構建一個映射,例如:

iex> letters = for <<x <- "AbCabCABc">>, x in ?a..?z, do: <<x>>
iex> Enum.reduce(letters, %{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{"a" => 1, "b" => 2, "c" => 1}

雖然上麵是straight-forward,但它的缺點是至少要遍曆數據兩次。如果您期望長字符串作為輸入,這可能會非常昂貴。

幸運的是,推導式也支持 :reduce 選項,這將允許我們將上述兩個步驟融合為一個步驟:

iex> for <<x <- "AbCabCABc">>, x in ?a..?z, reduce: %{} do
...>   acc -> Map.update(acc, <<x>>, 1, & &1 + 1)
...> end
%{"a" => 1, "b" => 2, "c" => 1}

當給定:reduce鍵時,其值用作初始累加器,必須將do塊更改為使用->子句,其中->的左側接收上一次迭代的累加值,右側的表達式必須返回新的累加器值。一旦沒有更多元素,則返回最終的累加值。如果根本沒有元素,則返回初始累加器值。

相關用法


注:本文由純淨天空篩選整理自elixir-lang.org大神的英文原創作品 Kernel.SpecialForms.for(args)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。