Вы завернули rs
в вектор. Таким образом, s
будет привязан ко всей последовательности, а не к отдельным записям карты. Поэтому, когда вы звоните val
, он не знает, что делать с последовательностью. Отсюда и исключение. Это должно работать:
(with-connection db
(with-query-results rs ["select category from users group by category"]
(doall
(for [rec rs
s rec]
(do
(println (val s)))))))
Однако уродливые doall
и do
вокруг for
должны звонить в колокол, чтобы что-то можно было улучшить. И действительно, for
используется для создания другой ленивой последовательности. Это плохо работает с побочными эффектами, как вы и предполагали в своем примере. Вы должны использовать doseq
в этом случае.
(with-connection db
(with-query-results rs ["select category from users group by category"]
(doseq [rec rs
s rec]
(println (val s)))))
Интерфейс для привязок doseq
идентичен интерфейсу for
. Однако он выполняет вещи немедленно и, таким образом, немедленно реализует любые побочные эффекты. Если вы поместите несколько выражений в тело для for, вы должны заключить его в do
. Это напоминание о том, что тело должно создавать ценность. Несколько выражений, однако, указывают на побочные эффекты. doseq
поэтому оборачивает тело в do
для вас. Таким образом, вы можете легко иметь несколько выражений. Для иллюстрации:
(doall
(for [s seq-of-maps]
(do
(println (key s))
(println (val s)))))
(doseq [s seq-of-maps]
(println (key s))
(println (val s)))))
Как правило: вам нужны побочные эффекты? Ищите вещи, начинающиеся с do
!
Как правило 2: если что-то выглядит некрасиво (см. Сравнение выше), это должно звучать как колокол.