2009-11-06 4 views
46

Скажем, у меня есть LazySeq из java.lang.Character какКак преобразовать LazySeq символов в строку в Clojure?

(\b \ \! \/ \b \ \% \1 \9 \/ \. \i \% \$ \i \space \^@) 

Как я могу преобразовать это в String? Я попытался очевидное

(String. my-char-seq) 

но он бросает

java.lang.IllegalArgumentException: No matching ctor found for class java.lang.String (NO_SOURCE_FILE:0) 
[Thrown class clojure.lang.Compiler$CompilerException] 

Я думаю, потому что конструктор Струнный ожидает примитивный символ [] вместо LazySeq. Итак, я попробовал что-то вроде

(String. (into-array my-char-seq)) 

, но это исключение. Проблема в том, что в-массив возвращает java.lang.Character [] вместо примитива char []. Это разочарование, потому что я на самом деле генерировать свою последовательность символов, как этот

(map #(char (Integer. %)) seq-of-ascii-ints) 

В принципе у меня есть след от Интс, представляющих ASCII символов; 65 = A и т. Д. Вы можете видеть, что я явно использую функцию принуждения типа примитива (char x).

Что это означает, что моя карты функция возвращает примитивный символ но Clojure карты функции в целом возвращается в java.lang.Character объекта.

ответ

97

Это работает:

(apply str my-char-seq) 

В основном, ул называет ToString() на каждом из своих аргументах, а затем присоединяет их. Здесь мы используем применим, чтобы передать символы в последовательности как args к str.

10

Другой способ заключается в использовании clojure.string/join, следующим образом:

(require '[clojure.string :as str]) 
(assert (= (vec "abcd")    [\a \b \c \d])) 
(assert (= (str/join (vec "abcd")) "abcd")) 
(assert (= (apply str (vec "abcd")) "abcd")) 

Существует альтернативная форма clojure.string/join, которая принимает сепаратор.См:

http://clojuredocs.org/clojure_core/clojure.string/join

Для более сложных проблем, вы можете также пожелать LookAt strcatfrom the Tupelo library:

(require '[tupelo.core :as t]) 
(prn (t/strcat "I " [ \h \a nil \v [\e \space (byte-array [97]) 
        [ nil 32 "complicated" (Math/pow 2 5) '("str" nil "ing") ]]])) 
;=> "I have a complicated string" 
3

В особом случае, если основной тип последовательности в вопросе clojure.lang.StringSeq вы можете также делают:

(.s (my-seq)) 

, который чрезвычайно эффективен, поскольку он просто тянет o ut публичное конечное поле CharSequence из класса Clojure StringSeq.

Пример:

(type (seq "foo")) 
=> clojure.lang.StringSeq 

(.s (seq "foo")) 
=> "foo" 

(type (.s (seq "foo"))) 
=> java.lang.String 

пример последствий синхронизации (и обратите внимание на разницу при использовании типа подсказки):

(time 
    (let [q (seq "xxxxxxxxxxxxxxxxxxxx")] 
    (dotimes [_ 1000000] 
     (apply str q)))) 
"Elapsed time: 620.943971 msecs" 
=> nil 

(time 
    (let [q (seq "xxxxxxxxxxxxxxxxxxxx")] 
    (dotimes [_ 1000000] 
     (.s q)))) 
"Elapsed time: 1232.119319 msecs" 
=> nil 

(time 
    (let [^StringSeq q (seq "xxxxxxxxxxxxxxxxxxxx")] 
    (dotimes [_ 1000000] 
     (.s q)))) 
"Elapsed time: 3.339613 msecs" 
=> nil