Thanks to Rachel Bowyer for contributing this chapter.
Clojure’s vector is one of the standout features of the language: performant, immutable and with a convenient literal syntax. Back in 2009 when Clojure 1.0 was launched, there was nothing else quite like it; and it set Clojure apart from earlier LISPs. Since then, other functional languages such as Scala [183] and Haskell [184] have added their own immutable vector.
Clojure’s vector stores elements sequentially, using zero-based indexing. It provides efficient read, write and append making direct access to the index of the element. It also supports efficient delete from the tail of the vector (with pop), but not from other locations (for which the best workaround is to use “subvec”).
The literal syntax for a vector consists of merely enclosing a space separated list of the elements within a pair of square brackets:
[:a :b :c] ; #1 ;; => [:a :b :c]
As well as being a data structure, a vector is also a function that looks up a value. It takes one argument, the zero based index, and if it is out of range then an IndexOutOfBoundsException
is thrown:
(ifn? []) ; #1 ;; true ([:a :b :c] 2) ; #2 ;; :c ([:a :b :c] 3) ; #3 ;; IndexOutOfBoundsException
Listing 12.1. Functions that operate on vectors