Spec-Zone.ru › Elixir 1.6

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

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

Атомы

Атомы в Elixir начинаются с двоеточия (:), за которым должны следовать некомбинируемые символы Unicode и подчёркивание. Атом может продолжать использовать последовательность символов Unicode, включая цифры, подчёркивание и @. Атомы могут заканчиваться на ! или ?. См. Синтаксис Unicode для формального описания. Символы Unicode требуют OTP 20.

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

Если за двоеточием следует двойная или одинарная кавычка, атом может состоять из любого символа, например, :"++olá++".

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

Строки

Строки в одну строку в Elixir записываются в двойных кавычках, например, "foo". Любая двойная кавычка внутри строки должна быть экранирована с помощью \. Строки поддерживают символы Unicode и хранятся как двоичные данные в кодировке 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'. Любая одинарная кавычка внутри строки должна быть экранирована с помощью \. Списки символов представляют собой список целых чисел, каждое целое число представляет собой символ Unicode.

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

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

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

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

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

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

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

Структуры

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

Выражения

Переменные

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

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

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

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

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

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

Операторы

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

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

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

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

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

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

Псевдонимы

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

Рекомендации по именованию 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.

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

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

1_000_000
#=> 1000000

0xABCD
#=> 43981 (Hexadecimal base)

0o01234567
#=> 342391 (Octal base)

0b10101010
#=> 170 (Binary base)

?é
#=> 233 (Unicode codepoint)

Эти конструкции существуют только на уровне синтаксиса. Все вышеприведённые примеры представлены как соответствующие целые числа в 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.6.6/syntax-reference.html

Spec-Zone.ru

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