Одно отличие состоит в том, что conj
принимает любое количество аргументов для вставки в коллекцию, а cons
принимает только один:
(conj '(1 2 3) 4 5 6)
; => (6 5 4 1 2 3)
(cons 4 5 6 '(1 2 3))
; => IllegalArgumentException due to wrong arity
Другое отличие заключается в классе возвращаемого значения:
(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList
(class (cons 4 '(1 2 3))
; => clojure.lang.Cons
Обратите внимание, что они на самом деле не взаимозаменяемы;в частности, clojure.lang.Cons
не реализует clojure.lang.Counted
, поэтому count
для него больше не является операцией с постоянным временем (в этом случае он, вероятно, уменьшится до 1 + 3 - 1 получается из линейного обхода за первыйЭлемент, 3 происходит от (next (cons 4 '(1 2 3))
, являющегося PersistentList
и, таким образом, Counted
).
Намерение, стоящее за именами, заключается в том, что, как я полагаю, cons
означает "против"1018 * 1 , тогда как conj
означает соединение (или предмет в коллекцию).seq
, создаваемый с помощью cons
, начинается с элемента, переданного в качестве первого аргумента, и имеет в качестве next
/ rest
часть вещь, полученную в результате применения seq
ко второму аргументу;как показано выше, все это класса clojure.lang.Cons
.Напротив, conj
всегда возвращает коллекцию примерно того же типа, что и переданная ему коллекция.(Грубо говоря, поскольку PersistentArrayMap
будет превращено в PersistentHashMap
, как только оно превысит 9 записей.)
1 Традиционно, в мире Лисп, cons
cons (транспортирует пару), поэтому Clojure отходит от традиции Lisp, поскольку ее функция cons
создает последовательность, которая не имеет традиционной cdr
.Обобщенное использование cons
для обозначения «создания записи того или иного типа для удержания нескольких значений вместе» в настоящее время повсеместно используется при изучении языков программирования и их реализации;это то, что имеется в виду, когда упоминается "избегать употребления".