Elixir:使用`:into`作为范围生成器(数字)

李岡諭*_*李岡諭 0 elixir

让我们在Elixir中看到以下表达式:

iex> for n <- 1..30, rem(n, 3) == 0, do: n * 10
[30, 60, 90, 120, 150, 180, 210, 240, 270, 300]
Run Code Online (Sandbox Code Playgroud)

我尝试使用:into可选项来总结它们,但它失败了:

# expect to get `1650` from `[30, 60, 90, 120, 150, 180, 210, 240, 270, 300]`
iex> for n <- 1..30, rem(n, 3) == 0, into: 0, do: n * 10
** (Protocol.UndefinedError) protocol Collectable not implemented for 0
    (elixir) lib/collectable.ex:1: Collectable.impl_for!/1
    (elixir) lib/collectable.ex:46: Collectable.into/1
Run Code Online (Sandbox Code Playgroud)

是否可以使用:into组合枚举数值的结果?

如果有,怎么样?

Dog*_*ert 5

不,into只能用于收集Collectable类型.整数不是Collectable.

你可以Enum.sum/1在这里使用,但你可能已经知道:

iex(1)> Enum.sum(for n <- 1..30, rem(n, 3) == 0, do: n * 10)
1650
Run Code Online (Sandbox Code Playgroud)

Enum.reduce/3但是,如果你的目标是不创建一个中间列表,你可以在这里使用:

Enum.reduce(1..30, 0, fn n, acc -> if(rem(n, 3) == 0, do: acc + n * 10, else: acc) end)
1650
Run Code Online (Sandbox Code Playgroud)

编辑:整数可以通过Collectable添加行为来实现,但我不推荐它,因为(1)这个实现是全局的,(2)没有明显的方法可以"收集"到一个整数中,你可以这样做好用倍增而不是加法.仅用于学习目的,这里是如何实现Collectable具有附加行为的整数:

defimpl Collectable, for: Integer do
  def into(acc) do
    {acc, fn
      acc, {:cont, x} -> acc + x
      acc, _ -> acc
    end}
  end
end

IO.inspect for n <- 1..30, rem(n, 3) == 0, into: 0, do: n * 10
Run Code Online (Sandbox Code Playgroud)

输出:

1650
Run Code Online (Sandbox Code Playgroud)