После того, как я более-менее понял синтаксис языка, пришло время взяться за разбор типов данных (надо же информацию как-то хранить).
Строки, числа, nil (а еще логический тип)
Как и в любом нормальном языке, в Clojure присутствует все необходимое для хранения информации. Начну с числовых типов.
Sample code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
user=> ; Целочисленный тип
user=> 10
10
user=> ; Тип чисел с плавающей запятой
user=> 10.0
10.0
user=> ; Тип вещественных дробей
user=> 10/7
10/7
user=> ; Тип, взятый из java.math.BigDecimal
user=> 10M
10M
user=> ; Тип BigInt
user=> 10N
10N
Воспользуемся оператором class, дабы узнать каждый тип:
Sample code
1
2
3
4
5
6
7
8
9
10
user=> (class 10M)
java.math.BigDecimal
user=> (class 10/7)
clojure.lang.Ratio
user=> (class 10.0)
java.lang.Double
user=> (class 10)
java.lang.Long
user=> (class 10N)
clojure.lang.BigInt
Прекрасно, не правда ли? Теперь взглянем на логический тип. Ему соответствуют два значения: true false. Однако существует один важный момент - nil, о котором мы говорили ранее, также относится к false. Cтроки в языке мы рассматривали ранее. Это был некоторый текст, заключенный между двойными кавычками.
map
Немаловажным типом для нас является тип map, позволяющий хранить пары ключ-значение. Ключем и значением может быть любой тип, будь то строка, другой map или даже функция. Чтобы инициализировать карту, мы поступим следующим образом:
undefined
Пары ключ-значение можно разделять запятыми, это видно по последним двум примерам. Получать значения из карты можно функциями get или get-in. Единственное отличие второй функции от первой в том, что она позволяет получать значения из вложенных карт:
undefined
Векторы
С векторами все просто - он очень похож на обычный массив с нулевой индексацией. Не буду долго тянуть, потому вот вполне понятные примеры:
Sample code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
user=> [10 11 9 20 30]
[101192030]
user=> ; Это нормально, хранить смешанные типы данных
user=> [10 10.0 10N 10M "TEN"]
[1010.010N 10M "TEN"]
user=> ; Функция get работает также, как и для карт
user=> ; nth работает как и get, НО! Если индекс выходит за пределы, будет сгенерировано любимое нами IndexOutOfBoundsException
user=> (nth [10 20] 1)
20
Списки
О них тоже пока много сказать не могу. Скажу только вот что - как они объявляются и какие основные функции мы можем применять:
Sample code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
user=> `(10 20 30)
(102030)
user=> ; get здесь уже не работает
user=> (get `(10 20 30) 1)
nil
user=> (nth `(10 20 30) 1)
20
user=> ; Элемент добавляется в начало, а не конец
user=> (conj `(10 20 30) "A")
("A"102030)
user=> ; А так мы можем узнать размер практически любой структуры данных, будь то строка, список, вектор или множество
user=> (count `(10 20 30))
3
user=> (list 10 20 30)
(102030)
Множество
Думаю, вникнув в суть предыдущих структур данных, для множества хватит просто примеров:
Sample code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
user=> (set [10 10 20 20 30])
#{20 30 10}
user=> ; В отличие от обычного множества, хеш- и сортированное множество не удаляет дубликаты
user=> (sorted-set [10 10 20 20 30])
#{[10 10 20 20 30]}
user=> (hash-set [10 10 20 20 30])
#{[10 10 20 20 30]}
user=> (get (set [10 10 20 20 30]) 10)
10
user=> (get (set [10 10 20 20 30]) 100)
nil
user=> (count (set [10 10 20 20 30]))
3
user=> (conj (set [10 10 20 20 30]) 100)
#{20 100 30 10}
user=> (conj (set [10 10 20 20 30]) "a" "b" "A")
#{20 "a" "b" "A" 30 10}
Заключение
Думаю, на этом пора заканчивать, все это вполне интересно, но следующей не менее крупной темой будет тема функций - создание, вызов, анонимные функции, макрофункции и прочие прелести.