Spec-Zone.ru › Elixir 1.18

Исходный код Справочник по синтаксису

Синтаксис Elixir разработан для простого преобразования в абстрактное синтаксическое дерево (AST). Это означает, что синтаксис Elixir в основном унифицирован с небольшим количеством конструкций «синтаксического сахара», чтобы уменьшить шум в общих выражениях Elixir.

В данном документе рассматриваются все синтаксические конструкции Elixir в качестве справки, а затем обсуждается их точное представление в AST.

Зарезервированные слова

Ниже приведены зарезервированные слова языка Elixir. Они подробно описаны в этом руководстве, но здесь они суммированы для удобства:

  • true, false, nil - используются как атомы
  • when, and, or, not, in - используются как операторы
  • fn - используется для определения анонимных функций
  • do, end, catch, rescue, after, else - используются в блоках do-end

Типы данных

Числа

Целые числа (1234) и числа с плавающей точкой (123.4) в Elixir представляются как последовательность цифр, которые могут быть разделены подчеркиванием для улучшения читаемости, например 1_000_000. Целые числа никогда не содержат точки (.) в своем представлении. Числа с плавающей точкой содержат точку и по крайней мере одну цифру после точки. Числа с плавающей точкой также поддерживают научную запись, например, 123.4e10 или 123.4E10.

Атомы

Неопределенные атомы начинаются с двоеточия (:) и должны быть немедленно последованные буквой Юникода или символом подчеркивания. Атом может продолжаться, используя последовательность букв, цифр, подчеркиваний и @. Атомы могут заканчиваться ! или ?. Действительные неопределенные атомы: :ok, :ISO8601, и :integer?.

Если за двоеточием сразу следует пара двойных или одинарных кавычек, окружающих имя атома, то атом считается определенным. В отличие от неопределенного атома, этот атом может состоять из любого символа Юникода (а не только букв), например :'🌢 Elixir', :"++olá++", и :"123".

Определенные и неопределенные атомы с одинаковым именем считаются эквивалентными, поэтому :atom, :"atom", и :'atom' представляют один и тот же атом. Единственный нюанс заключается в том, что компилятор будет предупреждать, когда кавычки используются в атомах, которые не нуждаются в цитировании.

Все операторы в Elixir также являются допустимыми атомами. Примеры допустимых операторов: :foo, :FOO, :foo_42, :foo@bar, и :++. Недопустимые примеры: :@foo (@ не разрешен в начале), :123 (цифры не разрешены в начале) и :(*) (не является допустимым оператором).

true, false, и nil — зарезервированные слова, которые представлены атомами :true, :false и :nil соответственно.

Чтобы узнать больше о всех символах Юникода, разрешенных в атомах, ознакомьтесь с документом Синтаксис Юникода.

Строки

Однострочные строки в Elixir записываются между двойными кавычками, например "foo". Любая двойная кавычка внутри строки должна быть экранирована с помощью \. Строки поддерживают символы Юникода и хранятся как двоичные данные в кодировке UTF-8.

Многострочные строки в Elixir записываются с тремя двойными кавычками и могут содержать неэкранированные кавычки внутри них. Результирующая строка будет заканчиваться новой строкой. Отступ последнего """ используется для удаления отступа из внутренней строки. Например:

iex> test = """
...>     this
...>     is
...>     a
...>     test
...> """
"    this\n    is\n    a\n    test\n"
iex> test = """
...>     This
...>     Is
...>     A
...>     Test
...>     """
"This\nIs\nA\nTest\n"

Строки всегда представляются самими собой в AST.

Списки символов

Списки символов — это списки неотрицательных целых чисел, где каждое целое число представляет собой код символа Юникода.

iex(6)> 'abc' === [97, 98, 99]
true

Списки символов записываются в одинарных кавычках, например 'foo'. Любая одинарная кавычка внутри строки должна быть экранирована с помощью \. Многострочные списки символов записываются с тремя одинарными кавычками ('''), так же, как и многострочные строки. Однако этот синтаксис устарел в пользу сигила списков символов ~c.

Списки символов всегда представляются самими собой в AST.

Для получения более подробной информации, пожалуйста, прочитайте раздел «Списки символов» в модуле List.

Списки, кортежи и двоичные данные

Структуры данных, такие как списки, кортежи и двоичные данные, отмечаются соответственно разделителями [...], {...}, и <<...>>. Каждый элемент разделяется запятой. Также разрешена конечная запятая, как в [1, 2, 3,].

Карты и списки ключевых слов

Карты используют обозначение %{...} и каждое значение-ключ задается парами, помеченными =>, например %{"hello" => 1, 2 => "world"}.

Как списки ключевых слов (список кортежей из двух элементов, где первый элемент является атомом), так и карты с атомными ключами поддерживают обозначение ключевых слов, где символ двоеточия : перемещается в конец атома. %{hello: "world"} эквивалентно %{:hello => "world"}, а [foo: :bar] эквивалентно [{:foo, :bar}]. Мы обсудим ключевые слова в последующих разделах.

Структуры

Структуры построены на основе синтаксиса карт путем передачи имени структуры между % и {. Например, %User{...}.

Выражения

Переменные

Переменные в Elixir должны начинаться с символа подчеркивания или буквы Юникода, которая не находится в верхнем регистре или в стиле заголовков. Переменная может продолжаться, используя последовательность букв, цифр и символов подчеркивания. Переменные могут заканчиваться ? или !. Чтобы узнать больше о всех символах Юникода, разрешенных в переменных, ознакомьтесь с документом Синтаксис Юникода.

Рекомендации по именованию в Elixir рекомендуют использовать переменные в формате snake_case.

Неквалифицированные вызовы (локальные вызовы)

Неквалифицированные вызовы, такие как add(1, 2), должны начинаться с символов и затем следовать тем же правилам, что и переменные, которые необязательно сопровождаются скобками, а затем аргументами.

Скобки обязательны для вызовов нулевой арности (т.е. вызовов без аргументов), чтобы избежать неоднозначности с переменными. Если используются скобки, они должны следовать имени функции без пробелов. Например, add (1, 2) — это синтаксическая ошибка, так как (1, 2) обрабатывается как недопустимый блок, который пытается передать в качестве единственного аргумента функции add.

Рекомендации по именованию в Elixir рекомендуют использовать вызовы в формате snake_case.

Операторы

Как и многие языки программирования, Elixir также поддерживает операторы как неквалифицированные вызовы со своими правилами приоритета и ассоциативности. Конструкции, такие как =, when, & и @ — это просто операторы. См. страницу Операторы для получения полной справки.

Квалифицированные вызовы (удаленные вызовы)

Квалифицированные вызовы, такие как Math.add(1, 2), должны начинаться с символов и затем следовать тем же правилам, что и переменные, которые необязательно сопровождаются скобками, а затем аргументами. Квалифицированные вызовы также поддерживают операторы, такие как Kernel.+(1, 2). Elixir также позволяет писать имя функции в двойных или одинарных кавычках, что позволяет использовать любые символы между кавычками, например Math."++add++"(1, 2).

Подобно неквалифицированным вызовам, скобки имеют разный смысл для вызовов нулевой арности (т.е. вызовов без аргументов). Если используются скобки, например mod.fun(), это означает вызов функции. Если скобки опущены, например map.field, это означает доступ к полю карты.

Рекомендации по именованию в Elixir рекомендуют использовать вызовы в формате snake_case.

Псевдонимы

Псевдонимы — это конструкции, которые расширяются до атомов во время компиляции. Псевдоним String расширяется до атома :"Elixir.String". Псевдонимы должны начинаться с прописной буквы ASCII, за которой могут следовать любые буквы, цифры или символы подчеркивания ASCII. Символы, не являющиеся ASCII, не поддерживаются в псевдонимах.

Несколько псевдонимов могут быть объединены с ., например MyApp.String, и расширяются до атома :"Elixir.MyApp.String". Точка фактически является частью имени, но также может использоваться для композиции. Если вы определите alias MyApp.Example, as: Example в своем коде, то Example всегда будет расширяться до :"Elixir.MyApp.Example", а Example.String будет расширяться до :"Elixir.MyApp.Example.String".

Рекомендации по именованию в Elixir рекомендуют использовать псевдонимы в формате CamelCase.

Атрибуты модуля

Атрибуты модуля — это специфичные для модуля данные хранения, которые записываются как композиция унарного оператора @ с переменными и локальными вызовами. Например, чтобы записать в атрибут модуля под названием foo, используйте @foo "value", а чтобы прочитать из него, используйте @foo. Поскольку атрибуты модулей записываются с использованием существующих конструкций, они следуют тем же правилам, что и операторы, переменные и локальные вызовы.

Блоки

Блоки — это несколько выражений Elixir, разделенных символами новой строки или точкой с запятой. Новый блок может быть создан в любой момент с помощью скобок.

Стрелка слева направо

Стрелка слева направо (->) используется для установления связи между левой и правой частями, обычно называемыми предложениями. Левая часть может иметь ноль, одну или более аргументов; правая часть — ноль, одну или более выражений, разделенных новой строкой. -> может появляться один или более раз между одним из следующих разделителей: do-end, fn-end или (-). Когда используется ->, между этими разделителями допускаются только другие предложения. Смешение предложений и регулярных выражений является недопустимым синтаксисом.

Он виден в конструкциях case и cond между do и end:

case 1 do
  2 -> 3
  4 -> 5
end

cond do
  true -> false
end

Виден в спецификациях типов между ( и ):

(integer(), boolean() -> integer())

Он также используется между fn и end для создания анонимных функций:

fn
  x, y -> x + y
end

Сигилы

Сигилы начинаются с ~ и следуют за одной строчной буквой или одной или более заглавными буквами, немедленно за которыми следует одна из следующих пар:

  • ( и )
  • { и }
  • [ и ]
  • < и >
  • " и "
  • ' и '
  • | и |
  • / и /

После закрытия пары можно указать ноль или более ASCII-букв и цифр в качестве модификатора. Сигилы выражаются как вызовы без квалификаторов, префикс sigil_, где первый аргумент — содержимое сигила в виде строки, а второй аргумент — список целых чисел в качестве модификаторов:

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

~s/f#{"o"}o/
~S/f#{"o"}o/

Сигилы полезны для кодирования текста со своими правилами экранирования, такими как регулярные выражения, даты и время, и другие.

Абстрактное синтаксическое дерево Elixir

Синтаксис Elixir разработан для прямого преобразования в абстрактное синтаксическое дерево (AST). AST Elixir — это обычная структура данных Elixir, состоящая из следующих элементов:

  • атомы — например, :foo
  • целые числа — например, 42
  • вещественные числа — например, 13.1
  • строки — например, "hello"
  • списки — например, [1, 2, 3]
  • кортежи из двух элементов — например, {"hello", :world}
  • кортежи из трех элементов, представляющие вызовы или переменные, как описано ниже

Основной структурный блок AST Elixir — это вызов, например:

sum(1, 2, 3)

который представляется кортежем из трех элементов:

{:sum, meta, [1, 2, 3]}

первый элемент — атом (или другой кортеж), второй элемент — список кортежей из двух элементов с метаданными (например, номерами строк), третий — список аргументов.

Мы можем получить AST для любого выражения Elixir, вызвав quote:

quote do
  sum()
end
#=> {:sum, [], []}

Переменные также представлены кортежем из трех элементов и комбинацией списков и атомов, например:

quote do
  sum
end
#=> {:sum, [], Elixir}

Можно заметить, что переменные также представлены кортежем, за исключением третьего элемента, который является атомом, выражающим контекст переменной.

В ходе этой части мы рассмотрим множество конструкций синтаксиса Elixir и их представления AST.

Операторы

Операторы обрабатываются как вызовы без квалификаторов:

quote do
  1 + 2
end
#=> {:+, [], [1, 2]}

Обратите внимание, что . также является оператором. Дистанционные вызовы используют точку в AST с двумя аргументами, где второй аргумент всегда является атомом:

quote do
  foo.bar(1, 2, 3)
end
#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}

Вызов анонимных функций использует точку в AST с одним аргументом, отражая тот факт, что имя функции «отсутствует» справа от точки:

quote do
  foo.(1, 2, 3)
end
#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}

Псевдонимы

Псевдонимы представлены вызовом __aliases__ с каждым сегментом, разделенным точкой, как аргумент:

quote do
  Foo.Bar.Baz
end
#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}

quote do
  __MODULE__.Bar.Baz
end
#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}

Все аргументы, кроме первого, гарантированно являются атомами.

Структуры данных

Помните, что списки — это литералы, поэтому они представлены сами по себе в AST:

quote do
  [1, 2, 3]
end
#=> [1, 2, 3]

Кортежи имеют собственное представление, за исключением кортежей из двух элементов, которые представлены сами по себе:

quote do
  {1, 2}
end
#=> {1, 2}

quote do
  {1, 2, 3}
end
#=> {:{}, [], [1, 2, 3]}

Двоичные данные имеют представление, аналогичное кортежам, но помечены :<<>> вместо :{}:

quote do
  <<1, 2, 3>>
end
#=> {:<<>>, [], [1, 2, 3]}

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

quote do
  %{1 => 2, 3 => 4}
end
#=> {:%{}, [], [{1, 2}, {3, 4}]}

Блоки

Блоки представлены вызовом __block__ с каждой строкой в качестве отдельного аргумента:

quote do
  1
  2
  3
end
#=> {:__block__, [], [1, 2, 3]}

quote do 1; 2; 3; end
#=> {:__block__, [], [1, 2, 3]}

Стрелка слева направо

Стрелка слева направо (->) представляется аналогично операторам, за исключением того, что они всегда являются частью списка, его левая часть представляет список аргументов, а правая — выражение.

Например, в case и cond:

quote do
  case 1 do
    2 -> 3
    4 -> 5
  end
end
#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}

quote do
  cond do
    true -> false
  end
end
#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}

Между ( и ):

quote do
  (1, 2 -> 3
   4, 5 -> 6)
end
#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]

Между fn и end:

quote do
  fn
    1, 2 -> 3
    4, 5 -> 6
  end
end
#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}

Квалифицированные кортежи

Квалифицированные кортежи (foo.{bar, baz}) представлены вызовом {:., [], [expr, :{}]}, где expr представляет левую часть точки, а аргументы — элементы внутри фигурных скобок. Это используется в Elixir для предоставления нескольких псевдонимов:

quote do
  Foo.{Bar, Baz}
end
#=> {{:., [], [{:__aliases__, [], [:Foo]}, :{}]}, [], [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]}

Блоки do-end

Блоки Elixir do-end эквивалентны ключевым словам в качестве последнего аргумента вызова функции, где содержимое блока заключено в скобки. Например:

if true do
  this
else
  that
end

эквивалентно:

if(true, do: (this), else: (that))

Хотя приведенная выше конструкция не требует пользовательских узлов в AST Elixir, они ограничены только определенными ключевыми словами, перечисленными ниже:

  • after
  • catch
  • else
  • rescue

Вы найдете их в конструкциях, таких как receive, try, и других. Более примеры можно найти в главе «Дополнительный синтаксис».

← Предыдущая страница Шаблоны и условия
Следующая страница → Справочник по спецификациям типов

Скачать версию 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/syntax-reference.html

Spec-Zone.ru

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