November 23, 2020 · Elixir Learn By Example

Learn By Example: Understanding the ampersand in Elixir (capture operator)

Learn By Example: Understanding the ampersand in Elixir (capture operator)
  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket

Seeing the ampersand for the first time in Elixir I wanted to dig deep into what it meant. The first & effectively either gets a reference to the original function or starts an anonymous function. Any ampersand after the first that references the positional argument passed to it. You could use this to write very concise anonymous functions.

Here's a couple of examples:

messages = ["One", "Two"]

no_capture_operator = fn msg ->
  IO.inspect(msg, label: 'no_capture_operator')
  %{itemValue: msg}
end
# no_capture_operator: "One"
# no_capture_operator: "Two"

messages |> Enum.map(no_capture_operator)

new_messages = messages |> Enum.map(&%{itemValue: &1})

IO.inspect(new_messages)
# [%{itemValue: "One"}, %{itemValue: "Two"}]

new_messages = messages |> Enum.map(fn msg ->
  IO.inspect(msg)
  %{itemValue: msg}
end)
# "One"
# "Two"

IO.inspect(new_messages, label: "new_messages =")
# new_messages =: [%{itemValue: "One"}, %{itemValue: "Two"}]

message_func = fn msg ->
  IO.inspect(msg)
  %{itemValue: msg}
end

messages |> Enum.map(&message_func.(&1))
# "One"
# "Two"

# the enum tuples have zero-based indexes, hence the + 1
message_with_odd_even = &%{itemValue: &1, type: (if rem(&2 + 1, 2) === 0, do: "even", else: "odd")}

msg_tuple = {"One", 0}

IO.inspect(message_with_odd_even.(elem(msg_tuple, 0), elem(msg_tuple, 1)))
# %{itemValue: "One", type: "odd"}

IO.inspect(message_with_odd_even.("One", 0))
# %{itemValue: "One", type: "odd"}

new_messages = messages |> Enum.with_index |> Enum.map(&message_with_odd_even.(elem(&1, 0), elem(&1, 1)))

IO.inspect(new_messages, label: 'new_messages 2 =')
# new_messages 2 =: [%{itemValue: "One", type: "odd"}, %{itemValue: "Two", type: "even"}]

messages |> Enum.each(&IO.inspect(&1, label: "label for " <> &1))
# label for One: "One"
# label for Two: "Two"

Read more at the official docs: https://elixir-lang.org/getting-started/modules-and-functions.html#function-capturing

Subscribe by Email

Get my latest content straight to your email

    We won't send you spam. Unsubscribe at any time.
    Powered By ConvertKit
    If you have any questions about this article