Исходный код Inspect протокол
Протокол Inspect преобразует структуру данных Elixir в алгебраическое представление.
Это обычно делается, когда вы хотите настроить, как ваши собственные структуры отображаются в логах и терминале.
В этом документе описано реализация протокола Inspect для ваших собственных структур данных. Чтобы узнать больше об использовании inspect, см. Kernel.inspect/2 и IO.inspect/2.
Представление Inspect
Обычно существует три варианта представления inspect. Для понимания рассмотрим следующую структуру User:
defmodule User do defstruct [:id, :name, :address] end
Наши варианты:
Вывести структуру, используя синтаксис Elixir, например:
%User{address: "Earth", id: 13, name: "Jane"}. Это стандартное представление и лучший вариант, если все поля структуры являются публичными.Вывести используя обозначение
#User<...>, например:#User<id: 13, name: "Jane", ...>. Это обозначение не генерирует допустимый код Elixir и обычно используется, когда структура имеет приватные поля (например, вы можете скрыть поле:address, чтобы защитить конфиденциальную информацию).Вывести структуру, используя синтаксис выражения, например:
User.new(13, "Jane", "Earth"). Это предполагает наличие функцииUser.new/3. Этот вариант в основном используется как альтернатива варианту 2 для представления пользовательских структур данных, таких какMapSet,Date.Rangeи другие.
Вы можете реализовать протокол Inspect для своих структур, соблюдая вышеуказанные соглашения. Вариант 1 является стандартным представлением, и вы можете быстро достичь варианта 2, унаследовав протокол Inspect. Для варианта 3 требуется собственная реализация.
Наследование
Протокол Inspect может быть унаследован для настройки порядка полей (по умолчанию по алфавиту) и скрытия определённых полей из структур, чтобы они не отображались в логах, результатах inspect и т.п. Последнее особенно полезно для полей, содержащих конфиденциальную информацию.
Поддерживаемые варианты:
:only— включать только указанные поля при отображении.:except— исключать указанные поля при отображении.:optional— (с версии v1.14.0) не включать поле, если оно соответствует своему значению по умолчанию. Это может упростить представление структуры за счёт скрытия информации.
Когда используются :only или :except для ограничения полей, структура будет выводиться с использованием обозначения #User<...>, так как структуру больше нельзя скопировать и вставить в качестве допустимого кода Elixir. Посмотрим пример:
defmodule User do
@derive {Inspect, only: [:id, :name]}
defstruct [:id, :name, :address]
end
inspect(%User{id: 1, name: "Jane", address: "Earth"})
#=> #User<id: 1, name: "Jane", ...>
Если используется только вариант :optional, структура всё ещё будет выводиться как %User{...}.
Пользовательская реализация
Вы также можете определить свою пользовательскую реализацию протокола, определив функцию inspect/2. Функция получает сущность для проверки, за которой следуют параметры проверки, представленные структурой Inspect.Opts. Построение алгебраического документа выполняется с помощью Inspect.Algebra.
Зачастую проверка структуры может быть реализована на основе существующих сущностей. Например, вот реализация MapSet для inspect/2:
defimpl Inspect, for: MapSet do
import Inspect.Algebra
def inspect(map_set, opts) do
concat(["MapSet.new(", Inspect.List.inspect(MapSet.to_list(map_set), opts), ")"])
end
end
Функция concat/1 взята из Inspect.Algebra и объединяет алгебраические документы вместе. В приведённом примере она объединяет строку "MapSet.new(", документ, возвращённый Inspect.Algebra.to_doc/2, и финальную строку ")". Следовательно, MapSet с числами 1, 2 и 3 будет выведен как:
iex> MapSet.new([1, 2, 3], fn x -> x * 2 end) MapSet.new([2, 4, 6])
Другими словами, представление inspect MapSet возвращает выражение, которое, при вычислении, создаёт сам MapSet.
Обработка ошибок
В случае ошибки при проверке вашей структуры Elixir поднимет ошибку ArgumentError и автоматически вернётся к исходному представлению структуры для вывода. Кроме того, будьте внимательны при отладке собственной реализации Inspect, так как вызовы IO.inspect/2 или dbg/1 могут вызвать бесконечную петлю (так как для проверки/отладки структуры данных нужно вызвать сам inspect).
Вот несколько советов:
Для отладки используйте
IO.inspect/2с опциейstructs: false, которая отключает пользовательскую печать и предотвращает рекурсивный вызов реализации Inspect.-
Чтобы получить доступ к основной ошибке в вашей пользовательской реализации
Inspect, вы можете вызвать протокол напрямую. Например, мы могли бы вызвать реализациюInspect.MapSetвыше как:Inspect.MapSet.inspect(MapSet.new(), %Inspect.Opts{})
Краткое описание
Типы
- t()
Все типы, которые реализуют этот протокол.
Функции
- inspect(term, opts)
Преобразует
termв алгебраическое представление.
Типы
t()Исходный код
@type t() :: term()
Все типы, которые реализуют этот протокол.
Функции
inspect(term, opts)Исходный код
@spec inspect(t(), Inspect.Opts.t()) :: Inspect.Algebra.t()
Преобразует term в алгебраическое представление.
Эта функция не должна вызываться напрямую, за исключением случаев реализации пользовательского inspect_fun для передачи в Inspect.Opts. Во всех остальных случаях следует использовать Inspect.Algebra.to_doc/2, так как она обрабатывает структуры и исключения.
© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/Inspect.html