Spec-Zone.ru › Elixir 1.14

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

Синтаксис 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". Псевдонимы должны начинаться с заглавной буквы 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]}]}

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

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

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

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

Все вышеперечисленные конструкции являются частью синтаксиса 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. Скобки необходимы при вызове анонимных функций, например, f.(1, 2, 3).

На практике разработчики предпочитают добавлять скобки к большинству своих вызовов. Они пропускаются в основном в управляющих конструкциях Elixir, таких как defmodule, if, case, и т. д., и в некоторых DSL.

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

Ключевые слова в 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.14.1/syntax-reference.html

Spec-Zone.ru

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