Spec-Zone.ru › Elixir 1.16

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

Синтаксис 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), должны начинаться с символов и затем следовать тем же правилам, что и переменные, за которыми необязательно следуют скобки, а затем аргументы. Квалифицированные вызовы также поддерживают операторы, такие как 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]}]}

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

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

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

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

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]

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

Чтобы быть допустимым синтаксисом ключевого слова, : не может предшествовать никакой пробелу (foo : 1 недопустимо) и должен следовать пробел (foo:1 недопустимо).

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

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, и другие.

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

Скачать версию ePub

Создано с помощью ExDoc (v0.32.2) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/syntax-reference.html

Spec-Zone.ru

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