5.6 Переменные

# Переменные

Присвоение имён полезно для вашего кода. С Sonic Pi это очень просто. Вы пишете желаемое имя, знак равенства, а затем то, что нужно запомнить:

```
sample_name = :loop_amen
```

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

```
sample_name = :loop_amen
sample sample_name
```

Есть три главных причины для использования переменных в Sonic Pi: присвоение значения, управление повторами и захват результатов операций.

## Присвоение значения

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

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

```
sleep 1.7533
```

Зачем указано число `1.7533`? Откуда оно взялось? Что оно означает? Теперь взгляните на этот пример:

```
loop_amen_duration = 1.7533
sleep loop_amen_duration
```

Вот теперь стало ясно, что значит `1.7533`. Это же продолжительность сэмпла `:loop_amen`! Конечно, вы могли бы заметить, почему бы просто не написать так:

```
sleep sample_duration(:loop_amen)
```

Это, безусловно, очень хороший способ выразить намерения кода.

## Управление повторами

Часто вы видите много повторений в своем коде. Когда необходимо что-то поменять, то делать это приходится во многих местах. Посмотрите на следующее:

```
sample :loop_amen
sleep sample_duration(:loop_amen)
sample :loop_amen, rate: 0.5
sleep sample_duration(:loop_amen, rate: 0.5)
sample :loop_amen
sleep sample_duration(:loop_amen)
```

Много чего мы делаем с `:loop_amen`! Но что если мы захотим послушать как это будет звучать с другим замкнутым сэмплом, таким как `:loop_garzul`? Пришлось бы найти и заменить все `:loop_amen` на `:loop_garzul`. Этим можно заняться, если больше нечего делать. А как насчет живого выступления? Иногда время - это непозволительная роскошь. Особенно, если вы хотите, чтобы люди продолжали танцевать.

Ну, а если бы вы записали свой код так:

```
sample_name = :loop_amen
sample sample_name
sleep sample_duration(sample_name)
sample sample_name, rate: 0.5
sleep sample_duration(sample_name, rate: 0.5)
sample sample_name
sleep sample_duration(sample_name)
```

Он делает совершенно то же самое (попробуйте сами). Зато тут есть возможность заменить строку `sample_name = :loop_amen` на `sample_name = :loop_garzul`, что приведёт к реальным изменениям во многих местах. Вот что даёт нам магия переменных.

## Захват результатов

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

```
sd = sample_duration(:loop_amen)
```

Теперь можно вставлять `sd` везде, где нам нужна длительность сэмпла `:loop_amen`.

Вероятно, ещё более важно то, что переменная разрешает нам сохранить результат вызова `play` или `sample`:

```
s = play 50, release: 8
```

Мы захватили и запомнили `s` как переменную, которая позволяет управлять синтом, пока он играет:

```
s = play 50, release: 8
sleep 2
control s, note: 62
```

В следующей главе мы рассмотрим подробнее управление синтами.


## Внимание: переменные и потоки

Хотя переменные хороши для присвоения имени и сохранения результатов, важно знать что они обычно должны использоваться в потоке. Например, *не делайте так*:

```
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :sorted do
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end
live_loop :shuffled do
  a = a.shuffle
  sleep 0.5
end
```

В примере выше мы присвоили ряд чисел переменной 'a' и затем использовали её в  двух отдельных 'live_loop`s'.  В первом живом цикле каждые '0,5' секунды мы сортируем кольцевой список (1, 2, 3, 4, 5, 6), затем отображаем результат в журнале.  Если ты запустишь код, ты увидишь, что выведенный список *не всегда отсортирован!*. Это может быть для тебя сюрпризом, ведь иногда список выводится отсортированным, а иногда нет. Это называется недетерминированным поведением и является результатом неприятной проблемы называемой гонкой состояний.  Проблема заключается в том, что второй живой цикл также работает с нашим кольцевым списком (в данном случае перемешивает его) и на момент вывода на экран список может быть как отсортирован, так и перемешан. Оба живых цикла  соревнуются сделать разные вещи с одной переменной и каждый раз 'побеждает' разный цикл.

Есть два решения. Первое: *не использовать одну переменную в разных живых циклах или потоках*. Например, код ниже всегда выводит отсортированный список, поскольку каждый живой цикл имеет собственную отдельную переменную:

```
live_loop :shuffled do
  a = (ring 6, 5, 4, 3, 2, 1)
  a = a.shuffle
  sleep 0.5
end
live_loop :sorted do
  a = (ring 6, 5, 4, 3, 2, 1)
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end
```

Однако, иногда мы хотим поделиться чем-то между потоками. Например, текущей тональностью, BMP, синтом и т.д. В этом случае решением будет воспользоваться специальными потоко-безопасными состояниями системы Sonic Pi через функции 'get' и 'set. Это будет осуждаться в разделе 10.
