--- title: Clojure Lists They Are Everything localeTitle: Clojure Списки Они все --- Списки являются фундаментальными для Clojure. Clojure - это Lisp, а Lisps были первоначально использованы для обработки списка. Все в Лиспе - это список! ``` (def foo "bar") ``` Этот кусок кода на самом деле является списком! Так что все между двумя круглыми скобками в Clojure. Интересно, не так ли? Это то, что делает Lisps настолько интересным - вы можете легко написать код, который генерирует новый код, потому что генерировать код так же просто, как составить список. ## Создание фактического списка Проблема в том, что, поскольку все это список в Clojure, что-то вроде этого вернет ошибку: ``` (1 2 3 4 5) ; => ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn ``` Какое ужасное сообщение об ошибке. Что REPL пытается сказать нам, это: «1 не является функцией, и ее нельзя превратить в одну». Поскольку все в Lisp является списком, первый элемент любого списка рассматривается как функция, например `def` , `+` или `str` , поэтому, если мы пишем `(1 2 3 4 5)` , он обрабатывает первый элемент ( `1` ) как функции, которой это явно не является. Мы можем решить это двумя способами. Один использует функцию `list` для построения списка, например, используя `str` для объединения строк вместе. ``` (list 1 2 3 4 5) ; => (1 2 3 4 5) ``` Вы также можете использовать цитирование. Цитирование списка в основном говорит компилятору, что этот список _не_ является вызовом функции, и он не должен оценивать какой-либо из кода внутри него. ``` '(1 2 3 4 5) ; => (1 2 3 4 5) ``` Интересно, что вы также можете вызывать вызовы функций. Вот как работают макросы. Они довольно сложны и заслуживают собственной статьи, поэтому мы не будем здесь останавливаться. ``` ;; Without a ' to quote it, this would return "foobarbaz". '(str "foo" "bar" "baz") ; => (str "foo" "bar" "baz") ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [IDEOne!](https://ideone.com/6c7UxY) ## Добавление в список Списки предназначены для добавления, а не для добавления. Нет никакого реального способа добавления в список. Вы можете перейти к списку с помощью `cons` . `conj` также работает, но это предназначено для векторов, а `cons` быстрее для списков. ``` (cons 1 '(2 3 4)) ; => (1 2 3 4) ``` ## Извлечение из списков Вы извлекаете элементы из списков с помощью `nth` . `get` не работает в списках, поскольку списки предназначены для последовательного доступа, а не для произвольного доступа. Обратите внимание, что `nth` работает с векторами, но медленнее, чем `get` из-за этого. ``` (nth '(1 2 3 4) 0) ; => 1 ``` ## Преобразование других коллекций в списки Функция `list` не может преобразовать другие коллекции в списки, потому что она пытается построить список с использованием аргументов, которые ему даны. При пересылке `list` коллекция вернет список, содержащий эту коллекцию. ``` (list [1 2 3 4 5]) ; => ([1 2 3 4 5]) ``` Для преобразования в список используйте функцию `seq` . ``` (seq [1 2 3 4 5]) ; => (1 2 3 4 5) ``` ## Ленивые последовательности Clojure имеет блестящую функцию, называемую «ленивые последовательности». Ленивая последовательность - это список, элементы которого не сгенерированы, пока вы не обратитесь к элементу последовательности позже, и в этот момент он оценивает все элементы последовательности до тех пор, пока вы не захотите. Это позволяет создавать «бесконечные» последовательности! `range` - это, пожалуй, самая простая ленивая последовательность. Он содержит все числа. ``` (range 10) ; => (0 1 2 3 4 5 6 7 8 9) (range -5 5) ; => (-5 -4 -3 -2 -1 0 1 2 3 4) ``` Вы можете использовать ленивые последовательности, чтобы делать действительно классные вещи, например, генерировать ленивую последовательность всех чисел фибоначчи. ``` (def fibs (lazy-cat [0 1] (map + (rest fibs) fibs))) (take 10 fibs) ;; this means, "evaluate the first 10 fibonacci numbers." ; => (0 1 1 2 3 5 8 13 21 34) ``` Этот пример немного продвинут, и вы не должны его понимать, если вы новичок. Это просто пример того, что вы можете сделать с ленивыми последовательностями. Возможно, вы все равно это поймете! ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [IDEOne!](https://ideone.com/jwpvt8) ## Когда использовать список? Использование вектора обычно предпочтительнее использования списка, так как нет никакого риска, что компилятор случайно оценивает вектор как функцию, и быстрее получить доступ к произвольным элементам вектора. Списки наиболее полезны в трех случаях: * Создание кода с использованием макроса. * Создание «бесконечных» ленивых последовательностей. * Предоставление элементов коллекции. | [![:point_left:](//forum.freecodecamp.com/images/emoji/emoji_one/point_left.png?v=2 ": Point_left:") Предыдущая](//forum.freecodecamp.com/t/clojure-collections/18411) | [![:book:](//forum.freecodecamp.com/images/emoji/emoji_one/book.png?v=2 ":книга:") Главная ![:book:](//forum.freecodecamp.com/images/emoji/emoji_one/book.png?v=2 ":книга:")](//forum.freecodecamp.com/t/clojure-resources/18422) | [следующий ![:point_right:](//forum.freecodecamp.com/images/emoji/emoji_one/point_right.png?v=2 ": Point_right:")](//forum.freecodecamp.com/t/clojure-vectors/18421) | | [Коллекции](//forum.freecodecamp.com/t/clojure-collections/18411) | [Содержание](//forum.freecodecamp.com/t/clojure-resources/18422) | [Векторы](//forum.freecodecamp.com/t/clojure-vectors/18421) |