Кольцевые списки

# Кольцевые списки

Интересной разновидностью списков являются кольца. Если вы раньше занимались программированием, то наверняка сталкивались с кольцевым буфером или кольцевым массивом. Здесь мы узнаем про кольцевой список - это быстро и просто.

В предыдущем разделе о списках мы видели, как можно извлечь из них элементы, используя механизм индексирования:

```
puts [52, 55, 59][1]
```

Так, а что произойдет, если вы захотите извлечь индекс `100`? Там явно нет элемента с индексом 100, так как у нашего списка только три элемента. Поэтому Sonic Pi вернет вам `nil`, что означает "ничто".

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

```
counter = 0
notes = [52, 55, 59]
```

Теперь мы можем использовать счётчик, чтобы получить доступ к нотам в нашем списке:

```
puts notes[counter]
```

Здорово, мы получили `52`. Теперь давайте увеличим наш счётчик и получим другую ноту:

```
counter = (inc counter)
puts notes[counter]
```

Супер, теперь мы получили `55` и если мы сделаем так снова, получим `59`. Однако, если после этого мы увеличим счётчик ещё раз, мы выйдем за пределы нашего списка и получим `nil`. Но что, если нам нужно вернуться к началу списка и снова начинать извлекать элементы по кругу? Вот для этого и нужны кольца.

## Создание колец

Мы можем создавать кольца одним из двух способов. Либо используем функцию `ring` с элементами кольца в качестве параметров:

```
(ring 52, 55, 59)
```

Либо можем взять обычный список и преобразовать его в кольцо, передав ему `.ring` сообщение:

```
[52, 55, 59].ring
```

## Индексирование колец

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

```
(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59
```

## Использование колец

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

## Гаммы и аккорды тоже кольца

Полезно знать, что списки, возвращаемые `scale` и `chord` также являются кольцами и позволяют получить к ним доступ с помощью произвольных индексов.

## Конструкторы колец

В дополнение к `ring` существует ряд других функций, которые будут создавать кольца для нас.

* `range` предлагает вам указать начальную точку, конечную точку и размер шага.
* `bools` позволяет использовать `1` и `0`, чтобы кратко представлять логические переменные.
* `knit` позволяет связывать в последовательности повторяющиеся значения.
* `spread` создает кольцо логических значений с Евклидовым распределением.

Взгляните на их соответствующую документацию для получения дополнительной информации.

