Skip to content

Commit

Permalink
Adds sigils tranlation, refs wunsh#6
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn committed Jul 27, 2017
1 parent 5bcf51a commit 4e162c5
Showing 1 changed file with 188 additions and 0 deletions.
188 changes: 188 additions & 0 deletions sigils.md
@@ -0,0 +1,188 @@
---
title: Сигилы
---

# Сигилы

Мы уже знаем, что в Эликсирe есть строки с двойными кавычками и списки символов с одинарными кавычками. Однако, есть и другие структуры, у которых есть текстовое представление. Например, атомы, которые в основном создаются как `:atom`.

Одна из целей Эликсира - быть расширяемым. Разработчики должны иметь возможность расширить язык таким образом, чтобы решить любую задачу. Компьютерные науки стали слишком широкой областью, чтобы ядро любого языка смогло вместить в себя все решения всех возможных проблем. Однако, если сделать язык расширяемым, то разработчики, компании и сообщества сами смогут добавить в него все необходимое.

В текущей главе, мы рассмотрим сигилы - один из встроенных в язык механизмов для работы с текстовыми представлениями. Сигилы начинаются с символа тильда (`~`), после которого идет буква (которая идентифицирует сигил) и разделитель. Опционально, после разделителя могут быть добавлены еще и модификаторы.

## Регулярные выражения

Самый часто-используемый сигил в Эликсире - сигил [регулярных выражений](https://en.wikipedia.org/wiki/Regular_Expressions): `~r`.

```elixir
# Регулярное выражение, которое находит в строки "foo" или "bar":
iex> regex = ~r/foo|bar/
~r/foo|bar/
iex> "foo" =~ regex
true
iex> "bat" =~ regex
false
```

Эликсир предоставляет совместимый с Перл синтаксис регулярных выражений, который реализован в библиотеке [PCRE](http://www.pcre.org/). Регулярные выражения поддерживают модификаторы. Например, модификатор `i` делает регулярное выражение нечувствительным к регистру:

```elixir
iex> "HELLO" =~ ~r/hello/
false
iex> "HELLO" =~ ~r/hello/i
true
```

В [модуле Regex](https://hexdocs.pm/elixir/Regex.html) доступно больше информации о других модификаторах и операциях с регулярными выражениями.

Пока что во всех примерах мы использовали `/` для разделения сигилов. Однако, сигилы поддерживают 8 разных типов разделителей:

```elixir
~r/hello/
~r|hello|
~r"hello"
~r'hello'
~r(hello)
~r[hello]
~r{hello}
~r<hello>
```

Причина, по которой сигилы поддерживают разные типы разделителей, заключается в возможности писать код без экранирования. Регулярное выражение с прямыми слешами записанное в виде `~r(^https?://)` читается гораздо проще, чем такое же выражение в другой форме записи `~r/^https?:\/\//`. Аналогично, если в регулярном выражении есть прямые слеши и группы (которые используют `()`), то можно использовать двойные кавычки вместо слешей.

## Строки, списки символов и сигил списка слов

Кроме регулярных выражений в языке Эликсир есть три других сигила.

### Строки

Сигил `~s` используется для создания строк, также как и двойные кавычки. Сигил `~s` полезен, когда в самой строке есть двойные кавычки:

```elixir
iex> ~s(this is a string with "double" quotes, not 'single' ones)
"this is a string with \"double\" quotes, not 'single' ones"
```

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

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

```elixir
iex> ~c(this is a char list containing 'single quotes')
'this is a char list containing \'single quotes\''
```

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

Сигил `~w` используется для создания списка слов (сами слова - обычные строки). Внутри сигила `~w` слова разделены пробелами:

```elixir
iex> ~w(foo bar bat)
["foo", "bar", "bat"]
```

Сигил `~w` поддерживает модификаторы `c`, `s` и `a` (списки символов, строки и атомы соответственно) для указания типа данных членов итогового списка:

```elixir
iex> ~w(foo bar bat)a
[:foo, :bar, :bat]
```

Кроме сигилов в нижнем регистре, Эликсир также поддерживает сигилы в верхнем регистре, чтобы работать с экранированием и интерполяцией. Оба сигила `~s` и `~S` вернут строку, с той разницей, что сигилы в верхнем регистре не поддерживают экранирование и интерполяцию:

```elixir
iex> ~s(String with escape codes \x26 #{"inter" <> "polation"})
"String with escape codes & interpolation"
iex> ~S(String without escape codes \x26 without #{interpolation})
"String without escape codes \\x26 without \#{interpolation}"
```

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

- `\\` – одинарный обратный слеш
- `\a` – звонок/тревога
- `\b` – бекспейс
- `\d` - удаление
- `\e` - выход
- `\f` - форма подачи
- `\n` – новая строка
- `\r` – возврат каретки
- `\s` – пробел
- `\t` – таб
- `\v` – вертикальный таб
- `\0` - нулевой байт
- `\xDD` - представляет один байт в восьмеричной записи (например `\x13`)
- `\uDDDD` и `\u{D...}` - представляют символ Юникода (например `\u{1F600}`)

В добавок, двойная кавычка внутри двойной кавычки должна быть экранирована как `\"`, аналогично и одинарная кавычка внутри одинарной кавычки `\'`. Тем не менее, лучше изменить разделители, чем использовать экранирование.

Сигилы также поддерживают heredocs, в качестве разделителей используются три двойных или одинарных кавычки:

```elixir
iex> ~s"""
...> this is
...> a heredoc string
...> """
```
Чаще всего сигилы heredoc используют для написания документации. Например, если в документации встречается какой-то символ экранирования, то в документации могут появиться ошибки, потому что придется экранировать его дважды:
```elixir
@doc """
Converts double-quotes to single-quotes.
## Examples
iex> convert("\\\"foo\\\"")
"'foo'"
"""
def convert(...)
```

Но если использовать сигил `~S`, то такой проблемы можно полностью избежать:
```elixir
@doc ~S"""
Converts double-quotes to single-quotes.
## Examples
iex> convert("\"foo\"")
"'foo'"
"""
def convert(...)
```

## Собственные сигилы

Как уже было сказано в самом начале, сигилы - расширяемы. На самом деле использование сигила `~r/foo/i` равнозначно вызову `sigil_r` с двоичными данными и списком символов в качестве аргументов:

```elixir
iex> sigil_r(<<"foo">>, 'i')
~r"foo"i
```

Мы можем обратиться к документации сигила `~r` через `sigil_r`:

```elixir
iex> h sigil_r
...
```

Можно создавать собственные сигилы: нужно создать функцию, которая бы следовала формату `sigil_{имя_индентификатора}`. К примеру, давайте создадим сигил `~i`, который возвращает целое число (с опциональным модификатором `n`, чтобы сделать число отрицательным):

```elixir
iex> defmodule MySigils do
...> def sigil_i(string, []), do: String.to_integer(string)
...> def sigil_i(string, [?n]), do: -String.to_integer(string)
...> end
iex> import MySigils
iex> ~i(13)
13
iex> ~i(42)n
-42
```

Сигилы могут быть использованы для выполнения работы на шаге компиляции. К примеру, регулярные выражения в Эликсире компилируются в производительные структуры, чтобы работать быстрее на шаге выполнения. Если вам интересен данный вопрос, то советуем изучить, как работают макросы, и посмотреть как реализованы сигилы в модуле `Kernel` (где реализованы все `sigil_*` функции).

0 comments on commit 4e162c5

Please sign in to comment.