Исходный код Access поведение
Доступ к данным по ключам.
Модуль Access определяет поведение для динамического доступа к ключам любого типа в структуре данных с помощью синтаксиса data[key].
Access поддерживает списки ключевых слов (Keyword) и карты (Map) по умолчанию. Ключевые слова поддерживают только атомарные ключи, ключи для карт могут быть любого типа. Оба возвращают nil если ключ не найден:
iex> keywords = [a: 1, b: 2]
iex> keywords[:a]
1
iex> keywords[:c]
nil
iex> map = %{a: 1, b: 2}
iex> map[:a]
1
iex> star_ratings = %{1.0 => "★", 1.5 => "★☆", 2.0 => "★★"}
iex> star_ratings[1.5]
"★☆"
Этот синтаксис очень удобен, так как он может быть вложен произвольно:
iex> keywords = [a: 1, b: 2] iex> keywords[:c][:unknown] nil
Это работает, потому что обращение к чему-либо по значению nil возвращает само значение nil:
iex> nil[:a] nil
Карты и структуры
Хотя синтаксис доступа разрешен в картах через map[key], если ваша карта состоит из предопределённых атомарных ключей, вы должны предпочитать доступ к этим атомарным ключам с помощью map.key вместо map[key], так как map.key будет генерировать ошибку, если ключ отсутствует (что не должно происходить, если ключи предопределены) или если map имеет значение nil.
Аналогично, поскольку структуры являются картами и структуры имеют предопределённые ключи, они допускают только синтаксис struct.key и не допускают синтаксис доступа struct[key].
Другими словами, синтаксис map[key] свободный, возвращая nil для отсутствующих ключей, в то время как синтаксис map.key строгий, генерируя ошибку как для значений nil, так и для отсутствующих ключей.
Чтобы преодолеть этот разрыв, Elixir предоставляет функции get_in/1 и get_in/2, которые могут проходить по вложенным структурам данных, даже при наличии nil:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users["john"].age)
27
iex> get_in(users["unknown"].age)
nil
Обратите внимание, что даже если пользователь не найден, get_in/1 вернула nil. Вне get_in/1 попытка получить доступ к полю .age в nil приведет к ошибке.
Функция get_in/2 идёт ещё дальше, позволяя смешивать разные обработчики доступа. Например, если у вас есть карта пользователя с ключами :name и :languages, вот как получить имена всех языков программирования:
iex> languages = [
...> %{name: "elixir", type: :functional},
...> %{name: "c", type: :procedural}
...> ]
iex> user = %{name: "john", languages: languages}
iex> get_in(user, [:languages, Access.all(), :name])
["elixir", "c"]
Этот модуль предоставляет удобные функции для обхода других структур, таких как кортежи и списки. Как мы увидим далее, их можно даже использовать для обновления вложенных структур данных.
Если вы хотите узнать больше о двойственной природе карт в Elixir, как они могут быть как для структурированных данных, так и для хранения пар ключ-значение, см. модуль Map.
Обновление вложенных структур данных
Синтаксис доступа также можно использовать с макросами Kernel.put_in/2, Kernel.update_in/2, Kernel.get_and_update_in/2 и Kernel.pop_in/1 для дальнейшей работы со значениями во вложенных структурах данных:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"].age, 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
Как показано в предыдущем разделе, вы также можете использовать функции Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2 и Kernel.get_and_update_in/3 для предоставления вложенных пользовательских обработчиков доступа. Например, если у вас есть карта пользователя с ключами :name и :languages, вот как глубоко перейти по карте и преобразовать все имена языков в верхний регистр:
iex> languages = [
...> %{name: "elixir", type: :functional},
...> %{name: "c", type: :procedural}
...> ]
iex> user = %{name: "john", languages: languages}
iex> update_in(user, [:languages, Access.all(), :name], &String.upcase/1)
%{
name: "john",
languages: [
%{name: "ELIXIR", type: :functional},
%{name: "C", type: :procedural}
]
}
См. функции key/1, key!/1, elem/1 и all/0 для некоторых доступных обработчиков.
Описание
Типы
Обработчики
- fetch(элемент, ключ)
Вызывается для доступа к значению, хранящемуся под
keyв данном элементеterm.- get_and_update(данные, ключ, функция)
Вызывается для доступа к значению по
keyи его одновременного обновления.- pop(данные, ключ)
Вызывается для удаления значения по
keyиз данной структуры данных.
Функции
- all()
Возвращает функцию, которая получает доступ ко всем элементам в списке.
- at(индекс)
Возвращает функцию, которая получает доступ к элементу по
index(нумерация с нуля) в списке.- at!(индекс)
То же, что и
at/1, за исключением того, что генерирует исключениеEnum.OutOfBoundsError, если данный индекс вне границ.- elem(индекс)
Возвращает функцию, которая получает доступ к элементу по заданному индексу в кортеже.
- fetch(контейнер, ключ)
Получает значение для данного ключа в контейнере (карта, список ключевых слов или структура, которая реализует поведение
Access).- fetch!(контейнер, ключ)
То же, что и
fetch/2, но возвращает значение напрямую или генерирует исключениеKeyError, еслиkeyне найден.- filter(функция)
Возвращает функцию, которая получает доступ ко всем элементам списка, соответствующим заданному предикату.
- find(предикат)
Возвращает функцию, которая получает доступ к первому элементу списка, соответствующему заданному предикату.
- get(контейнер, ключ, значение_по_умолчанию \\ nil)
Получает значение для данного ключа в контейнере (карта, список ключевых слов или структура, которая реализует поведение
Access).- get_and_update(контейнер, ключ, функция)
Получает и обновляет указанный ключ в
container(карта, список ключевых слов, структура, которая реализует поведениеAccess).- key(ключ, значение_по_умолчанию \\ nil)
Возвращает функцию, которая получает доступ к данному ключу в карте/структуре.
- key!(ключ)
Возвращает функцию, которая получает доступ к данному ключу в карте/структуре.
- pop(контейнер, ключ)
Удаляет запись с заданным ключом из контейнера (карта, список ключевых слов или структура, которая реализует поведение
Access).- slice(диапазон)
Возвращает функцию, которая получает доступ к всем элементам списка, которые находятся в заданном диапазоне.
Типы
access_fun(data, current_value)Source
@type access_fun(data, current_value) :: get_fun(data) | get_and_update_fun(data, current_value)
container()Source
@type container() :: keyword() | struct() | map()
get_and_update_fun(data, current_value)Source
@type get_and_update_fun(data, current_value) :: (:get_and_update,
data,
(term() -> term()) ->
{current_value,
new_data :: container()}
| :pop) get_fun(data)Source
@type get_fun(data) :: (:get, data, (term() -> term()) -> new_data :: container())
key()Source
@type key() :: any()
nil_container()Source
@type nil_container() :: nil
t()Source
@type t() :: container() | nil_container() | any()
value()Source
@type value() :: any()
Обработчики
fetch(term, key)Source
@callback fetch(term :: t(), key()) :: {:ok, value()} | :error Вызывается для доступа к значению, хранящемуся по ключу key в заданном термине term.
Эта функция должна вернуть {:ok, value}, где value — значение по ключу key, если ключ существует в термине, или :error если ключ не существует в термине.
Многие функции, определённые в модуле Access, внутренне вызывают эту функцию. Эта функция также используется при использовании синтаксиса доступа с квадратными скобками (structure[key]). Обработчик fetch/2, реализованный модулем, определяющим структуру structure, вызывается, и если он возвращает {:ok, value}, то возвращается value, или если он возвращает :error, то возвращается nil.
См. реализации Map.fetch/2 и Keyword.fetch/2 для примеров реализации этого обработчика.
get_and_update(data, key, function)Source
@callback get_and_update(data, key(), (value() | nil ->
{current_value, new_value :: value()} | :pop)) ::
{current_value, new_data :: data}
when current_value: value(), data: container() Вызывается для доступа к значению по ключу key и одновременного его обновления.
Реализация этого обработчика должна вызвать fun со значением по ключу key в переданной структуре data, или с nil если key не присутствует в ней. Эта функция должна вернуть либо {current_value, new_value}, либо :pop.
Если переданная функция возвращает {current_value, new_value}, возвращаемое значение этого обработчика должно быть {current_value, new_data}, где:
current_value— полученное значение (которое можно обработать перед возвращением)new_value— новое значение, которое нужно сохранить по ключуkeynew_data—dataпосле обновления значения ключаkeyнаnew_value.
Если переданная функция возвращает :pop, возвращаемое значение этого обработчика должно быть {value, new_data}, где value — значение по ключу key (или nil, если ключ не присутствует), а new_data — data без key.
См. реализации Map.get_and_update/3 или Keyword.get_and_update/3 для дополнительных примеров.
pop(data, key)Source
@callback pop(data, key()) :: {value(), data} when data: container() Вызывается для "удаления" значения по ключу key из заданной структуры данных.
Если key существует в заданной структуре data, реализация должна вернуть кортеж {value, new_data}, где value — значение, которое было по ключу key, а new_data — term без key.
Если key не присутствует в заданной структуре, должен быть возвращён кортеж {value, data}, где value — определённое реализацией значение.
См. реализации Map.pop/3 или Keyword.pop/3 для дополнительных примеров.
Функции
all()Source
@spec all() :: access_fun(data :: list(), current_value :: list())
Возвращает функцию, которая обращается ко всем элементам в списке.
Возвращаемая функция обычно передаётся в качестве аксессора для Kernel.get_in/2, Kernel.get_and_update_in/3 и аналогичных функций.
Примеры
iex> list = [%{name: "john"}, %{name: "mary"}]
iex> get_in(list, [Access.all(), :name])
["john", "mary"]
iex> get_and_update_in(list, [Access.all(), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{["john", "mary"], [%{name: "JOHN"}, %{name: "MARY"}]}
iex> pop_in(list, [Access.all(), :name])
{["john", "mary"], [%{}, %{}]}
Вот пример, который проходит по списку, удаляя чётные числа и умножая нечётные на 2:
iex> require Integer
iex> get_and_update_in([1, 2, 3, 4, 5], [Access.all()], fn num ->
...> if Integer.is_even(num), do: :pop, else: {num, num * 2}
...> end)
{[1, 2, 3, 4, 5], [2, 6, 10]}
Если доступная структура не является списком, генерируется ошибка:
iex> get_in(%{}, [Access.all()])
** (RuntimeError) Access.all/0 expected a list, got: %{} at(index)Source
@spec at(integer()) :: access_fun(data :: list(), current_value :: term())
Возвращает функцию, которая обращается к элементу по index (нумерация с нуля) в списке.
Обратите внимание, что поиск по индексу в списках выполняется за линейное время: чем больше список, тем дольше займёт доступ к его индексу. Поэтому операции с индексами обычно избегаются в пользу других функций в модуле Enum.
Возвращаемая функция обычно передаётся в качестве аксессора для Kernel.get_in/2, Kernel.get_and_update_in/3 и аналогичных функций.
Примеры
iex> list = [%{name: "john"}, %{name: "mary"}]
iex> get_in(list, [Access.at(1), :name])
"mary"
iex> get_in(list, [Access.at(-1), :name])
"mary"
iex> get_and_update_in(list, [Access.at(0), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"john", [%{name: "JOHN"}, %{name: "mary"}]}
iex> get_and_update_in(list, [Access.at(-1), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"mary", [%{name: "john"}, %{name: "MARY"}]}
at/1 также можно использовать для извлечения элементов из списка или ключей внутри списка:
iex> list = [%{name: "john"}, %{name: "mary"}]
iex> pop_in(list, [Access.at(0)])
{%{name: "john"}, [%{name: "mary"}]}
iex> pop_in(list, [Access.at(0), :name])
{"john", [%{}, %{name: "mary"}]}
Если индекс выходит за пределы границ, возвращается nil и функция обновления никогда не вызывается:
iex> list = [%{name: "john"}, %{name: "mary"}]
iex> get_in(list, [Access.at(10), :name])
nil
iex> get_and_update_in(list, [Access.at(10), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{nil, [%{name: "john"}, %{name: "mary"}]}
Если доступная структура не является списком, генерируется ошибка:
iex> get_in(%{}, [Access.at(1)])
** (RuntimeError) Access.at/1 expected a list, got: %{} at!(index)Source
@spec at!(integer()) :: access_fun(data :: list(), current_value :: term())
Аналогично at/1, но генерирует исключение Enum.OutOfBoundsError, если указанный индекс выходит за пределы границ.
Примеры
iex> get_in([:a, :b, :c], [Access.at!(2)]) :c iex> get_in([:a, :b, :c], [Access.at!(3)]) ** (Enum.OutOfBoundsError) out of bounds error
elem(index)Source
@spec elem(non_neg_integer()) :: access_fun(data :: tuple(), current_value :: term())
Возвращает функцию, которая обращается к элементу по указанному индексу в кортеже.
Возвращаемая функция обычно передаётся в качестве аксессора для Kernel.get_in/2, Kernel.get_and_update_in/3 и аналогичных функций.
Возвращаемая функция генерирует ошибку, если index выходит за пределы границ.
Обратите внимание, что извлечение элементов из кортежей невозможно и вызывает ошибку.
Примеры
iex> map = %{user: {"john", 27}}
iex> get_in(map, [:user, Access.elem(0)])
"john"
iex> get_and_update_in(map, [:user, Access.elem(0)], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"john", %{user: {"JOHN", 27}}}
iex> pop_in(map, [:user, Access.elem(0)])
** (RuntimeError) cannot pop data from a tuple
Если доступная структура не является кортежем, генерируется ошибка:
iex> get_in(%{}, [Access.elem(0)])
** (RuntimeError) Access.elem/1 expected a tuple, got: %{} fetch(container, key)Source
@spec fetch(container(), term()) :: {:ok, term()} | :error @spec fetch(nil_container(), any()) :: :error
Извлекает значение для данного ключа в контейнере (карта, ключевой список или структура, реализующая поведение Access).
Возвращает {:ok, value} , где value — значение по ключу key, если такой ключ существует, или :error, если key не найден.
Примеры
iex> Access.fetch(%{name: "meg", age: 26}, :name)
{:ok, "meg"}
iex> Access.fetch([ordered: true, on_timeout: :exit], :timeout)
:error fetch!(container, key)Source
@spec fetch!(container(), term()) :: term()
Аналогично fetch/2, но возвращает значение непосредственно или генерирует исключение KeyError, если key не найден.
Примеры
iex> Access.fetch!(%{name: "meg", age: 26}, :name)
"meg" filter(func)Source
@spec filter((term() -> boolean())) :: access_fun(data :: list(), current_value :: list())
Возвращает функцию, которая обращается ко всем элементам списка, соответствующим предоставленному предикату.
Возвращаемая функция обычно передаётся в качестве аксессора для Kernel.get_in/2, Kernel.get_and_update_in/3 и аналогичных функций.
Примеры
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
iex> get_in(list, [Access.filter(&(&1.salary > 20)), :name])
["francine"]
iex> get_and_update_in(list, [Access.filter(&(&1.salary <= 20)), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{["john"], [%{name: "JOHN", salary: 10}, %{name: "francine", salary: 30}]}
filter/1 также можно использовать для извлечения элементов из списка или ключей внутри списка:
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
iex> pop_in(list, [Access.filter(&(&1.salary >= 20))])
{[%{name: "francine", salary: 30}], [%{name: "john", salary: 10}]}
iex> pop_in(list, [Access.filter(&(&1.salary >= 20)), :name])
{["francine"], [%{name: "john", salary: 10}, %{salary: 30}]}
Если совпадений не найдено, возвращается пустой список, и функция обновления не вызывается
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
iex> get_in(list, [Access.filter(&(&1.salary >= 50)), :name])
[]
iex> get_and_update_in(list, [Access.filter(&(&1.salary >= 50)), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{[], [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]}
Если предикат не является функцией или имеет неверную арность, генерируется ошибка:
iex> get_in([], [Access.filter(5)]) ** (FunctionClauseError) no function clause matching in Access.filter/1
Если доступная структура не является списком, генерируется ошибка:
iex> get_in(%{}, [Access.filter(fn a -> a == 10 end)])
** (RuntimeError) Access.filter/1 expected a list, got: %{} find(predicate)Source
@spec find((term() -> as_boolean(term()))) :: access_fun(data :: list(), current_value :: term())
Возвращает функцию, которая обращается к первому элементу списка, соответствующему предоставленному предикату.
Возвращаемая функция обычно передаётся в качестве аксессора для Kernel.get_in/2, Kernel.get_and_update_in/3 и аналогичных функций.
Примеры
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
iex> get_in(list, [Access.find(&(&1.salary > 20)), :name])
"francine"
iex> get_and_update_in(list, [Access.find(&(&1.salary <= 40)), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"john", [%{name: "JOHN", salary: 10}, %{name: "francine", salary: 30}]}
find/1 также можно использовать для извлечения первого найденного элемента из списка или ключа внутри списка:
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
iex> pop_in(list, [Access.find(&(&1.salary <= 40))])
{%{name: "john", salary: 10}, [%{name: "francine", salary: 30}]}
Если совпадений не найдено, возвращается nil, и функция обновления не вызывается
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
iex> get_in(list, [Access.find(&(&1.salary >= 50)), :name])
nil
iex> get_and_update_in(list, [Access.find(&(&1.salary >= 50)), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{nil, [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]}
Если предикат не является функцией или имеет неверную арность, генерируется ошибка:
iex> get_in([], [Access.find(5)]) ** (FunctionClauseError) no function clause matching in Access.find/1
Если доступная структура не является списком, генерируется ошибка:
iex> get_in(%{}, [Access.find(fn a -> a == 10 end)])
** (RuntimeError) Access.find/1 expected a list, got: %{} get(container, key, default \\ nil)Source
@spec get(container(), term(), term()) :: term()
@spec get(nil_container(), any(), default) :: default when default: var
Получает значение для данного ключа в контейнере (карта, ключевой список или структура, реализующая поведение Access).
Возвращает значение по ключу key, если такой ключ существует, или default, если key не найден.
Примеры
iex> Access.get(%{name: "john"}, :name, "default name")
"john"
iex> Access.get(%{name: "john"}, :age, 25)
25
iex> Access.get([ordered: true], :timeout)
nil get_and_update(container, key, fun)Source
@spec get_and_update(data, key(), (value() | nil ->
{current_value, new_value :: value()} | :pop)) ::
{current_value, new_data :: data}
when data: container(), current_value: var Получает и обновляет указанный ключ в контейнере (карта, ключевой список, структура, реализующая поведение Access).
Аргумент fun получает значение key (или nil, если key отсутствует в container) и должен возвращать кортеж из двух элементов {current_value, new_value}: значение "получить" current_value (полученное значение, которое можно обработать перед возвращением) и новое значение для хранения по key (new_value). fun также может вернуть :pop, что означает, что текущее значение должно быть удалено из контейнера и возвращено.
Возвращаемое значение — кортеж из двух элементов: значение "получить", возвращённое fun, и новый контейнер с обновлённым значением по key.
Примеры
iex> Access.get_and_update([a: 1], :a, fn current_value ->
...> {current_value, current_value + 1}
...> end)
{1, [a: 2]} key(key, default \\ nil)Source
@spec key(key(), term()) :: access_fun(data :: struct() | map(), current_value :: term())
Возвращает функцию, которая обращается к данному ключу в карте/структуре.
Возвращаемая функция обычно передаётся в качестве аксессора для Kernel.get_in/2, Kernel.get_and_update_in/3 и аналогичных функций.
Возвращаемая функция использует значение по умолчанию, если ключ не существует. Это позволяет указать значения по умолчанию и безопасно пройти по отсутствующим ключам:
iex> get_in(%{}, [Access.key(:user, %{}), Access.key(:name, "meg")])
"meg"
Это также полезно при использовании функций обновления, позволяя нам вводить значения при прохождении по структуре данных для обновлений:
iex> put_in(%{}, [Access.key(:user, %{}), Access.key(:name)], "Mary")
%{user: %{name: "Mary"}}
Примеры
iex> map = %{user: %{name: "john"}}
iex> get_in(map, [Access.key(:unknown, %{}), Access.key(:name, "john")])
"john"
iex> get_and_update_in(map, [Access.key(:user), Access.key(:name)], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"john", %{user: %{name: "JOHN"}}}
iex> pop_in(map, [Access.key(:user), Access.key(:name)])
{"john", %{user: %{}}}
Если доступная структура не является картой или структурой, генерируется ошибка:
iex> get_in([], [Access.key(:foo)]) ** (BadMapError) expected a map, got: []
key!(key)Source
@spec key!(key()) :: access_fun(data :: struct() | map(), current_value :: term())
Возвращает функцию, которая обращается к заданному ключу в карте/структуре.
Возвращаемая функция обычно передаётся в качестве аксессора к Kernel.get_in/2, Kernel.get_and_update_in/3 и похожим функциям.
Аналогично key/2, но возвращаемая функция вызывает исключение, если ключ не существует.
Примеры
iex> map = %{user: %{name: "john"}}
iex> get_in(map, [Access.key!(:user), Access.key!(:name)])
"john"
iex> get_and_update_in(map, [Access.key!(:user), Access.key!(:name)], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"john", %{user: %{name: "JOHN"}}}
iex> pop_in(map, [Access.key!(:user), Access.key!(:name)])
{"john", %{user: %{}}}
iex> get_in(map, [Access.key!(:user), Access.key!(:unknown)])
** (KeyError) key :unknown not found in: %{name: "john"}
Примеры выше можно частично записать так:
iex> map = %{user: %{name: "john"}}
iex> map.user.name
"john"
iex> get_and_update_in(map.user.name, fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{"john", %{user: %{name: "JOHN"}}}
Однако, нельзя удалить поля с помощью нотации точек, так как подразумевается, что эти поля должны быть присутствовать. В любом случае, Access.key!/1 полезна, когда ключ заранее неизвестен и должен быть получен динамически.
Возникает ошибка, если доступная структура не является картой/структурой:
iex> get_in([], [Access.key!(:foo)]) ** (RuntimeError) Access.key!/1 expected a map/struct, got: []
pop(container, key)Source
@spec pop(data, key()) :: {value(), data} when data: container() Удаляет запись с заданным ключом из контейнера (карты, списка ключевых слов или структуры, реализующей поведение Access).
Возвращает кортеж, содержащий значение, связанное с ключом, и обновлённый контейнер. nil возвращается для значения, если ключ отсутствует в контейнере.
Примеры
С картой:
iex> Access.pop(%{name: "Elixir", creator: "Valim"}, :name)
{"Elixir", %{creator: "Valim"}}
Список ключевых слов:
iex> Access.pop([name: "Elixir", creator: "Valim"], :name)
{"Elixir", [creator: "Valim"]}
Неизвестный ключ:
iex> Access.pop(%{name: "Elixir", creator: "Valim"}, :year)
{nil, %{creator: "Valim", name: "Elixir"}} slice(range)Source
@spec slice(Range.t()) :: access_fun(data :: list(), current_value :: list())
Возвращает функцию, которая получает все элементы списка, находящиеся в заданном диапазоне.
Диапазон будет нормализован в соответствии с теми же правилами, что и в Enum.slice/2.
Возвращаемая функция обычно передаётся в качестве аксессора к Kernel.get_in/2, Kernel.get_and_update_in/3 и похожим функциям.
Примеры
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}, %{name: "vitor", salary: 25}]
iex> get_in(list, [Access.slice(1..2), :name])
["francine", "vitor"]
iex> get_and_update_in(list, [Access.slice(1..3//2), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{["francine"], [%{name: "john", salary: 10}, %{name: "FRANCINE", salary: 30}, %{name: "vitor", salary: 25}]}
slice/1 также может использоваться для извлечения элементов из списка или ключа внутри списка:
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}, %{name: "vitor", salary: 25}]
iex> pop_in(list, [Access.slice(-2..-1)])
{[%{name: "francine", salary: 30}, %{name: "vitor", salary: 25}], [%{name: "john", salary: 10}]}
iex> pop_in(list, [Access.slice(-2..-1), :name])
{["francine", "vitor"], [%{name: "john", salary: 10}, %{salary: 30}, %{salary: 25}]}
Если совпадения не найдено, возвращается пустой список, и функция обновления никогда не вызывается
iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}, %{name: "vitor", salary: 25}]
iex> get_in(list, [Access.slice(5..10//2), :name])
[]
iex> get_and_update_in(list, [Access.slice(5..10//2), :name], fn prev ->
...> {prev, String.upcase(prev)}
...> end)
{[], [%{name: "john", salary: 10}, %{name: "francine", salary: 30}, %{name: "vitor", salary: 25}]}
Возникает ошибка, если доступная структура не является списком:
iex> get_in(%{}, [Access.slice(2..10//3)])
** (ArgumentError) Access.slice/1 expected a list, got: %{}
Возникает ошибка, если шаг диапазона отрицательный:
iex> get_in([], [Access.slice(2..10//-1)]) ** (ArgumentError) Access.slice/1 does not accept ranges with negative steps, got: 2..10//-1
© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/Access.html