Kernel.get_in

You're seeing just the function get_in, go back to Kernel module for more information.

Specs

get_in(Access.t(), [term(), ...]) :: term()

Gets a value from a nested structure.

Uses the Access module to traverse the structures according to the given keys, unless the key is a function, which is detailed in a later section.

Examples

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["john", :age])
27

In case any of the keys returns nil, nil will be returned:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["unknown", :age])
nil

Note that get_in exists mostly for convenience and parity with functionality found in put_in and update_in. Given Elixir provides pattern matching, it can often be more expressive for deep data traversal, for example:

case users do
  %{"unknown" => %{age: age}} -> age
  _ -> default_value
end

Functions as keys

If a key is a function, the function will be invoked passing three arguments:

  • the operation (:get)
  • the data to be accessed
  • a function to be invoked next

This means get_in/2 can be extended to provide custom lookups. In the example below, we use a function to get all the maps inside a list:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get, data, next -> Enum.map(data, next) end
iex> get_in(users, [all, :age])
[27, 23]

If the previous value before invoking the function is nil, the function will receive nil as a value and must handle it accordingly.

The Access module ships with many convenience accessor functions, like the all anonymous function defined above. See Access.all/0, Access.key/2, and others as examples.

Working with structs

By default, structs do not implement the Access behaviour required by this function. Therefore, you can't do this:

get_in(some_struct, [:some_key, :nested_key])

The good news is that structs have predefined shape. Therefore, you can write instead:

some_struct.some_key.nested_key

If, by any chance, some_key can return nil, you can always fallback to pattern matching to provide nested struct handling:

case some_struct do
  %{some_key: %{nested_key: value}} -> value
  %{} -> nil
end