Ответ на использование (apply str ...)
обычно лучший. Но здесь есть дополнительная техника и «совет для профессионалов» о трех точках в (apply str ...)
.
Если содержимое строки наиболее естественно генерируется функциями print
(что не так в случае с ваш конкретный c примеров!), затем вы можете захватить его с помощью with-out-str
:
(with-out-str
(doseq [i (range 1 4)]
(print "|")
(print i))
(println "|")) ;; => "|1|2|3|\n"
Обычно (apply str ...)
является более идиоматическим c. Вы можете использовать весь гобелен функций последовательности (interleave
, interpose
, repeat
, cycle
, ...) и извлечь результат в виде строки с помощью (apply str ...)
. Но вы сталкиваетесь с проблемой, если последовательность содержит вложенные последовательности. Мы упоминаем эту проблему здесь, потому что есть два решения, которые определяют c для построения строк.
Чтобы быть понятным, вложенные последовательности "работают отлично" во всех отношениях, за исключением того, что str
делает с последовательностью может быть не то, что вы хотите. Например, чтобы построить «1 ------ 2 ------ 3»:
;; not quite right:
(apply str
(interpose
(repeat 2 "---")
(range 1 4))) ;; => "1(\"---\" \"---\")2(\"---\" \"---\")3"
Дело в том, что repeat
создал последовательность, которая interpose
покорно застряла между числа в большей последовательности и str
при обработке большей последовательности покорно записывают вложенные последовательности в синтаксис Clojure. Чтобы лучше контролировать, как вложенные последовательности становятся строковыми, вы можете заменить (repeat 2 "---")
на (apply str (repeat 2 "---"))
. Но если шаблон apply str
в пределах apply str
встречается снова и снова, это ухудшает отношение сигнал / шум программы. Альтернативой, которая может быть чище, является функция flatten
(может быть, это ее единственное использование c):
(apply str
(flatten
(interpose
(repeat 2 "---")
(range 1 4)))) ;; => "1------2------3"