Spec-Zone.ru › Elixir 1.18

Исходный код Структуры

Мы узнали о картах в предыдущих главах:

iex> map = %{a: 1, b: 2}
%{a: 1, b: 2}
iex> map[:a]
1
iex> %{map | a: 3}
%{a: 3, b: 2}

Структуры — это расширения, построенные на основе карт, которые обеспечивают проверки во время компиляции и значения по умолчанию.

Определение структур

Для определения структуры используется конструкция defstruct/1:

iex> defmodule User do
...>   defstruct name: "John", age: 27
...> end

Список ключевых слов, используемых с defstruct, определяет поля структуры и их значения по умолчанию. Структуры получают имя модуля, в котором они определены. В приведённом примере мы определили структуру с именем User.

Теперь мы можем создавать User структуры, используя синтаксис, похожий на синтаксис создания карт:

iex> %User{}
%User{age: 27, name: "John"}
iex> %User{name: "Jane"}
%User{age: 27, name: "Jane"}

Структуры обеспечивают гарантии во время компиляции, что в структуре будут разрешены только поля, определённые через defstruct:

iex> %User{oops: :field}
** (KeyError) key :oops not found expanding struct: User.__struct__/1

Доступ к структурам и их обновление

Структуры используют тот же синтаксис для доступа и обновления полей, что и карты с фиксированными ключами:

iex> john = %User{}
%User{age: 27, name: "John"}
iex> john.name
"John"
iex> jane = %{john | name: "Jane"}
%User{age: 27, name: "Jane"}
iex> %{jane | oops: :field}
** (KeyError) key :oops not found in: %User{age: 27, name: "Jane"}

При использовании синтаксиса обновления (|) Elixir знает, что новые ключи не будут добавлены в структуру, что позволяет картам, лежащим в основе, совместно использовать свою структуру в памяти. В приведённом примере john и jane используют одну и ту же структуру ключей в памяти.

Структуры также могут использоваться в шаблонах соответствия, как для соответствия значению конкретных ключей, так и для обеспечения того, что значение соответствия является структурой того же типа, что и значение, с которым производится соответствие.

iex> %User{name: name} = john
%User{age: 27, name: "John"}
iex> name
"John"
iex> %User{} = %{}
** (MatchError) no match of right hand side value: %{}

Подробнее о создании, обновлении и шаблонах соответствия для структур см. документацию по %/2.

Структуры представляют собой базовые карты

Структуры — это просто карты со специальным полем с именем __struct__, которое содержит имя структуры:

iex> is_map(john)
true
iex> john.__struct__
User

Однако структуры не наследуют никаких протоколов, которые используют карты. Например, вы не можете перечислить или получить доступ к структуре:

iex> john = %User{}
%User{age: 27, name: "John"}
iex> john[:name]
** (UndefinedFunctionError) function User.fetch/2 is undefined (User does not implement the Access behaviour)
             User.fetch(%User{age: 27, name: "John"}, :name)
iex> Enum.each(john, fn {field, value} -> IO.puts(value) end)
** (Protocol.UndefinedError) protocol Enumerable not implemented for %User{age: 27, name: "John"} of type User (a struct)

Структуры вместе с протоколами предоставляют одну из самых важных функций для разработчиков Elixir: полиморфизм данных. Об этом мы поговорим в следующей главе.

Значения по умолчанию и обязательные ключи

Если при определении структуры вы не указываете значение по умолчанию для ключа, предполагается значение nil:

iex> defmodule Product do
...>   defstruct [:name]
...> end
iex> %Product{}
%Product{name: nil}

Вы можете определить структуру, объединяющую как поля с явными значениями по умолчанию, так и неявные nil значения. В этом случае вы должны сначала указать поля, которые неявным образом имеют значение nil:

iex> defmodule User do
...>   defstruct [:email, name: "John", age: 27]
...> end
iex> %User{}
%User{age: 27, email: nil, name: "John"}

Выполнение в обратном порядке приведёт к синтаксической ошибке:

iex> defmodule User do
...>   defstruct [name: "John", age: 27, :email]
...> end
** (SyntaxError) iex:107: unexpected expression after keyword list. Keyword lists must always come last in lists and maps.

Вы также можете потребовать, чтобы определённые ключи были указаны при создании структуры с помощью атрибута модуля @enforce_keys:

iex> defmodule Car do
...>   @enforce_keys [:make]
...>   defstruct [:model, :make]
...> end
iex> %Car{}
** (ArgumentError) the following keys must also be given when building struct Car: [:make]
    expanding struct: Car.__struct__/1

Требование ключей обеспечивает простую гарантию во время компиляции, помогая разработчикам при построении структур. Это не выполняется при обновлениях и не обеспечивает никакой проверки значений.

← Предыдущая страница Атрибуты модуля
Следующая страница → Протоколы

Скачать версию ePub

Создано с помощью ExDoc (v0.36.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.18.1/structs.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API