Spec-Zone.ru › Elixir 1.10

Справочник синтаксиса

Синтаксис 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.

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

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

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

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

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

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

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

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

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

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

Структуры

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

Выражения

Переменные

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

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

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

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

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

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

Операторы

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

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

Квалифицированные вызовы, такие как Math.add(1, 2), должны начинаться с подчеркивания или буквы Юникода, которая не является заглавной или строчной. Вызов может продолжать использовать последовательность букв, цифр и подчеркиваний. Вызовы могут заканчиваться на ? или !. См. Синтаксис Юникода для формального описания.

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

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

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

Псевдонимы

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

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

Блоки

Блоки — это несколько выражений 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]}]}

Синтаксический сахар

Все конструкции выше являются частью синтаксиса Elixir и имеют собственное представление в составе AST Elixir. В этом разделе будут рассмотрены оставшиеся конструкции, которые «дезагрируют» в одну из рассмотренных выше конструкций. Другими словами, конструкции ниже могут быть представлены в коде Elixir более чем одним способом и сохранять эквивалентность AST.

Целые числа в других системах счисления и коды Юникода

Elixir позволяет целым числам содержать _ для разделения цифр и предоставляет удобства для представления целых чисел в других системах счисления:

1_000_000
#=> 1000000

0xABCD
#=> 43981 (Hexadecimal base)

0o01234567
#=> 342391 (Octal base)

0b10101010
#=> 170 (Binary base)

?é
#=> 233 (Unicode code point)

Эти конструкции существуют только на синтаксическом уровне. Все примеры выше представлены в виде своих базовых целых чисел в AST.

Синтаксис доступа

Синтаксис доступа представлен вызовом Access.get/2:

quote do
  opts[arg]
end
#=> {{:., [], [Access, :get]}, [], [{:opts, [], Elixir}, {:arg, [], Elixir}]}

Необязательные скобки

Elixir предоставляет необязательные скобки для вызовов без квалификации и с квалификацией.

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

Вышеупомянутое обрабатывается парсером так же, как sum(1, 2, 3).

То же самое относится к квалифицированным вызовам, таким как Foo.bar(1, 2, 3), которые эквивалентны Foo.bar 1, 2, 3. Однако помните, что скобки не являются необязательными для вызовов без квалификации без аргументов, таких как sum(). Удаление скобок для sum приводит к представлению в виде переменной sum, что означает, что они больше не будут эквивалентны.

Ключевые слова

Ключевые слова в Elixir — это список кортежей из двух элементов, где первый элемент — атом. Используя базовые конструкции, они представлялись бы так:

[{:foo, 1}, {:bar, 2}]

Однако Elixir вводит синтаксический сахар, где вышеприведённые ключевые слова могут быть написаны следующим образом:

[foo: 1, bar: 2]

Атомы с иностранными символами, например, пробелами, должны быть заключены в кавычки. Это правило также относится к ключевым словам:

[{:"foo bar", 1}, {:"bar baz", 2}] == ["foo bar": 1, "bar baz": 2]

Помните, что, поскольку списки и кортежи из двух элементов являются строковыми литералами, по определению ключевые слова также являются литералами (на самом деле, единственная причина, по которой кортежи из двух элементов являются строковыми литералами, заключается в поддержке ключевых слов как литералов).

Ключевые слова в качестве последних аргументов

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

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

то же самое, что

if(condition, [do: this, else: that])

что в свою очередь то же самое, что

if(condition, [{:do, this}, {:else, that}])

Блоки do/end

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

if true do
  this
else
  that
end

то же самое, что:

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

что мы рассмотрели в предыдущем разделе.

Скобки важны для поддержки нескольких выражений. Это:

if true do
  this
  that
end

то же самое, что:

if(true, do: (
  this
  that
))

Внутри блоков do/end вы можете ввести другие ключевые слова, такие как else используемое в if выше. Поддерживаемые ключевые слова между do/end статичны и следующие:

  • after
  • catch
  • else
  • rescue

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

Резюме

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

Мы также рассмотрели ряд синтаксических удобств, предоставляемых Elixir. Эти удобства позволяют нам писать

defmodule Math do
  def add(a, b) do
    a + b
  end
end

вместо

defmodule(Math, [
  {:do, def(add(a, b), [{:do, a + b}])}
])

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

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.10.4/syntax-reference.html

Spec-Zone.ru

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