Михил совершенно прав. Поскольку я не могу добавить код в комментарии к его ответу, вот что with-out-str
делает под прикрытием, так что вы можете сравнить его с вашей попыткой:
user=> (macroexpand-1 '(with-out-str (println "output")))
(clojure.core/let [s__4091__auto__ (new java.io.StringWriter)]
(clojure.core/binding [clojure.core/*out* s__4091__auto__]
(println "output")
(clojure.core/str s__4091__auto__)))
Ваш код связывал существующий стандартный поток вывода с переменной, печатал с этим потоком, а затем запрашивал у потока его значение через переменную; однако значение потока было, конечно, не байтами, которые ему были напечатаны. Поэтому with-out-str
временно связывает вновь созданный StringWriter
с *out*
и, наконец, запрашивает строковое значение этого временного средства записи.