Source Сигилы
Elixir предоставляет строки в двойных кавычках, а также концепцию charlists, которые определяются с помощью синтаксиса сигила ~c"hello world". В этой главе мы узнаем больше о сигилах и о том, как определить свои собственные.
Одна из целей Elixir — расширяемость: разработчики должны иметь возможность расширять язык для соответствия любому конкретному предметной области. Сигилы обеспечивают основу для расширения языка с помощью пользовательских текстовых представлений. Сигилы начинаются с тильды (~) символа, за которым следует либо одна строчная буква, либо одна или несколько заглавных букв, а затем разделитель. Дополнительные модификаторы добавляются после последнего разделителя.
Регулярные выражения
Наиболее распространённый сигил в Elixir — ~r, который используется для создания регулярных выражений:
# A regular expression that matches strings which contain "foo" or "bar": iex> regex = ~r/foo|bar/ ~r/foo|bar/ iex> "foo" =~ regex true iex> "bat" =~ regex false
Elixir предоставляет совместимые с Perl регулярные выражения (regex), как реализовано библиотекой PCRE. Regex также поддерживают модификаторы. Например, модификатор i делает регулярное выражение регистронезависимым:
iex> "HELLO" =~ ~r/hello/ false iex> "HELLO" =~ ~r/hello/i true
Посмотрите модуль Regex для получения дополнительной информации об других модификаторах и поддерживаемых операциях с регулярными выражениями.
До сих пор во всех примерах использовался / для разграничения регулярного выражения. Однако сигилы поддерживают 8 разных разделителей:
~r/hello/
~r|hello|
~r"hello"
~r'hello'
~r(hello)
~r[hello]
~r{hello}
~r<hello>
Причина поддержки различных разделителей заключается в предоставлении способа записи литералов без экранированных разделителей. Например, регулярное выражение с косыми чертами, как ~r(^https?://), читается, безусловно, лучше, чем ~r/^https?:\/\//. Аналогично, если регулярное выражение содержит косые черты и группы захвата (которые используют ()), вы можете выбрать двойные кавычки вместо скобок.
Сигилы строк, charlist и списков слов
Помимо регулярных выражений, Elixir поставляется с тремя другими сигилами.
Строки
Сигил ~s используется для генерации строк, как в двойных кавычках. Сигил ~s полезен, когда строка содержит двойные кавычки:
iex> ~s(this is a string with "double" quotes, not 'single' ones) "this is a string with \"double\" quotes, not 'single' ones"
Charlists
Сигил ~c — обычный способ представления charlist.
iex> [?c, ?a, ?t] ~c"cat" iex> ~c(this is a char list containing "double quotes") ~c"this is a char list containing \"double quotes\""
Списки слов
Сигил ~w используется для генерации списков слов (слова — это просто обычные строки). Внутри сигила ~w слова разделены пробелами.
iex> ~w(foo bar bat) ["foo", "bar", "bat"]
Сигил ~w также принимает модификаторы c, s и a (соответственно, для charlist, строк и атомов), которые задают тип данных элементов результирующего списка:
iex> ~w(foo bar bat)a [:foo, :bar, :bat]
Интерполяция и экранирование в сигилах строк
Elixir поддерживает некоторые варианты сигилов для обработки экранирования символов и интерполяции. В частности, сигилы с заглавными буквами не выполняют интерполяцию и экранирование. Например, хотя ~s и ~S возвращают строки, первый позволяет использовать коды экранирования и интерполяцию, а второй — нет:
iex> ~s(String with escape codes \x26 #{"inter" <> "polation"})
"String with escape codes & interpolation"
iex> ~S(String without escape codes \x26 without #{interpolation})
"String without escape codes \\x26 without \#{interpolation}"
Следующие коды экранирования могут использоваться в строках и charlist:
-
\\— одиночный обратный слэш -
\a— звонок/сигнал -
\b— возврат на один символ назад -
\d— удалить -
\e— экранирование -
\f— перевод страницы -
\n— перевод строки -
\r— возврат каретки -
\s— пробел -
\t— табуляция -
\v— вертикальная табуляция -
\0— нулевой байт -
\xDD— представляет собой один байт в шестнадцатеричном формате (например,\x13) -
\uDDDDи\u{D...}— представляют собой код Юникода в шестнадцатеричном формате (например,\u{1F600})
Помимо этого, двойная кавычка внутри строки в двойных кавычках должна быть экранирована как \", а аналогично одинарная кавычка внутри charlist в одинарных кавычках должна быть экранирована как \'. Тем не менее, лучше изменить разделители, как показано выше, чем экранировать их.
Сигилы также поддерживают heredocs, то есть три двойных или одинарных кавычки в качестве разделителей:
iex> ~s""" ...> this is ...> a heredoc string ...> """
Наиболее распространённый случай использования heredoc-сигилов — написание документации. Например, написание символов экранирования в документации быстро станет подверженным ошибкам из-за необходимости двойного экранирования некоторых символов:
@doc """
Converts double-quotes to single-quotes.
## Examples
iex> convert("\\\"foo\\\"")
"'foo'"
"""
def convert(...)
Использование ~S позволяет полностью избежать этой проблемы:
@doc ~S"""
Converts double-quotes to single-quotes.
## Examples
iex> convert("\"foo\"")
"'foo'"
"""
def convert(...)
Сигилы календаря
Elixir предлагает несколько сигилов для работы с различными форматами времени и дат.
Дата
Структура %Date{} содержит поля year, month, day, и calendar. Вы можете создать её с помощью сигила ~D.
iex> d = ~D[2019-10-31] ~D[2019-10-31] iex> d.day 31
Время
Структура %Time{} содержит поля hour, minute, second, microsecond, и calendar. Вы можете создать её с помощью сигила ~T.
iex> t = ~T[23:00:07.0] ~T[23:00:07.0] iex> t.second 7
NaiveDateTime
Структура %NaiveDateTime{} содержит поля как из Date, так и из Time. Вы можете создать её с помощью сигила ~N.
iex> ndt = ~N[2019-10-31 23:00:07] ~N[2019-10-31 23:00:07]
Почему это называется наивным? Потому что оно не содержит информации о часовом поясе. Поэтому указанная дата и время может вообще не существовать или существовать дважды в определённых часовых поясах — например, когда мы переводим время вперёд и назад на летнее время.
UTC DateTime
Структура %DateTime{} содержит те же поля, что и NaiveDateTime, с добавлением полей для отслеживания часовых поясов. Сигил ~U позволяет разработчикам создавать DateTime в часовом поясе UTC:
iex> dt = ~U[2019-10-31 19:59:03Z]
~U[2019-10-31 19:59:03Z]
iex> %DateTime{minute: minute, time_zone: time_zone} = dt
~U[2019-10-31 19:59:03Z]
iex> minute
59
iex> time_zone
"Etc/UTC"
Пользовательские сигилы
Как упоминалось в начале этой главы, сигилы в Elixir расширяемы. Фактически, использование сигила ~r/foo/i эквивалентно вызову sigil_r с бинарным значением и списком символов в качестве аргумента:
iex> sigil_r(<<"foo">>, [?i]) ~r"foo"i
Мы можем получить документацию для сигила ~r с помощью sigil_r:
iex> h sigil_r ...
Мы также можем предоставить свои собственные сигилы, реализовав функции, которые следуют схеме sigil_{character}. Например, давайте реализуем сигил ~i, который возвращает целое число (с необязательным модификатором n, чтобы сделать его отрицательным):
iex> defmodule MySigils do ...> def sigil_i(string, []), do: String.to_integer(string) ...> def sigil_i(string, [?n]), do: -String.to_integer(string) ...> end iex> import MySigils iex> ~i(13) 13 iex> ~i(42)n -42
Пользовательские сигилы могут быть либо одной строчной буквой, либо несколькими заглавными буквами.
Сигилы также могут использоваться для выполнения работы на этапе компиляции с помощью макросов. Например, регулярные выражения в Elixir компилируются в эффективное представление во время компиляции исходного кода, поэтому этот шаг пропускается на этапе выполнения. Если вас интересует эта тема, вы можете узнать больше о макросах и ознакомиться с тем, как сигилы реализованы в модуле Kernel (где определены функции sigil_*).
© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/sigils.html