문제

나는있다 java.util.HashMap 물체 m (호출에서 Java 코드로의 반환 값) 추가 키 값 쌍이있는 새 맵을 가져오고 싶습니다.

만약에 m Clojure지도 였는데 다음을 사용할 수있었습니다.

(assoc m "key" "value")

그러나 그것을 시도합니다 HashMap 제공 :

java.lang.classcastException : java.util.hashmap은 clojure.lang.associative에 캐스트 할 수 없습니다

운이 없습니다 seq 어느 하나:

(assoc (seq m) "key" "value")

java.lang.classcastException : clojure.lang.eratorseq는 clojure.lang.associative에 캐스트 할 수 없습니다

내가 할 수있는 유일한 방법은 사용하는 것이 었습니다. HashMap자신의 put, 그러나 그것은 돌아옵니다 void 그래서 나는 명시 적으로 돌아와야합니다 m:

(do (. m put "key" "value") m)

이것은 관용적 인 clojure 코드가 아니며, 수정하고 있습니다. m 새 맵을 만드는 대신.

작업하는 방법 a HashMap 더 clojure-ish 방식으로?

도움이 되었습니까?

해결책

Clojure는 Java 컬렉션을 SEQ- 가능하게 만들므로 Clojure 시퀀스 기능을 java.util.hashmap.

하지만 협회 예상 a clojure.lang.associative 따라서 먼저 변환해야합니다 java.util.hashmap 그것에 :

(assoc (zipmap (.keySet m) (.values m)) "key" "value")

편집 : 간단한 솔루션 :

(assoc (into {} m) "key" "value")

다른 팁

Java 코드와 인터페이스하는 경우 총알을 물고 Java Way를 사용해야 할 수도 있습니다. .put. 이것이 필사자의 죄가 아닙니다. Clojure는 당신과 같은 것을 제공합니다 do 그리고 . 특히 Java 코드를 쉽게 작업 할 수 있습니다.

assoc Clojure 데이터 구조에서만 작동합니다. 많은 작업이 약간의 변경으로 새로운 (불변) 사본을 만들기 위해 매우 저렴하게 만들었 기 때문입니다. Java Hashmaps는 같은 방식으로 작동하지 않습니다. 변경할 때마다 계속 복제해야합니다.

Java Mutation-Land에서 실제로 나가고 싶다면 (예 : 아마도이 해시 랩을 오랫동안 유지하고 있으며 Java가 모든 곳에서 전화를 걸지 않기를 원하거나, 당신은 그들을 통해 직렬화해야합니다. print 그리고 read, Clojure STM을 사용하여 스레드 안전 방식으로 작업하려고합니다.) Clojure 데이터 구조가 올바른 Java 인터페이스를 구현하여 서로 대화 할 수 있기 때문에 Java Hashmaps와 Clojure 해시 맵 사이를 쉽게 변환 할 수 있습니다.

user> (java.util.HashMap. {:foo :bar})
#<HashMap {:foo=:bar}>

user> (into {} (java.util.HashMap. {:foo :bar}))
{:foo :bar}

당신이 원한다면 do-작업을 마친 후에 작업중 인 객체를 반환하는 것과 같은 것은 사용할 수 있습니다. doto. 실제로, Java Hashmap 은이 기능의 공식 문서의 예로 사용됩니다. 이는 Java 객체를 사용하는 경우 (신중하게) 세계의 끝이 아니라는 또 다른 표시입니다.

clojure.core/doto
([x & forms])
Macro
  Evaluates x then calls all of the methods and functions with the
  value of x supplied at the front of the given arguments.  The forms
  are evaluated in order.  Returns x.

  (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))

몇 가지 가능한 전략 :

  1. 가능하면 돌연변이와 부작용을 단일 함수로 제한하십시오. 함수가 항상 동일한 입력이 주어진 동일한 값을 반환하는 경우 내부적으로 원하는대로 수행 할 수 있습니다. 때로는 배열이나 맵을 돌리는 것이 알고리즘을 구현하는 가장 효율적이거나 가장 쉬운 방법입니다. 당신은 세계 다른 지역에 "누출"부작용을하지 않는 한 여전히 기능 프로그래밍의 이점을 누릴 것입니다.

  2. 객체가 잠시 동안 주변에 있거나 다른 Clojure 코드와 잘 놀어야한다면, 가능한 빨리 Clojure 데이터 구조로 가져 와서 마지막 순간에 Java Hashmaps에 다시 캐스팅하십시오 (먹이를 먹을 때. 다시 Java로 돌아갑니다).

전통적인 방식으로 Java Hash지도를 사용해도 괜찮습니다.
(do (. m put "key" "value") m)
This is not idiomatic Clojure code, plus I'm modifying m instead of creating a new map.

실제로 수정 대상 데이터 구조를 수정하고 있습니다. Java의 해시 맵에는 구조 공유가 부족합니다 이를 통해 Clojures Map을 효율적으로 복사 할 수 있습니다. 이 작업을 수행하는 일반적으로 관용적 인 방법은 Java-Interop 기능을 사용하여 전형적인 Java 방식의 Java 구조와 함께 작동하거나 Clojure 구조로 깨끗하게 변환하여 기능적 클로 주행 방식으로 작업하는 것입니다. 물론 인생이 더 쉬워지고 더 나은 코드를 초래하지 않는 한; 그런 다음 모든 베팅이 꺼져 있습니다.

이것은 Clojure 버전과 Java의 메모리 특성을 비교하려고 할 때 해시 맵을 사용하여 작성한 일부 코드입니다 (그러나 Clojure에서 사용).

(import '(java.util Hashtable))
(defn frequencies2 [coll]
    (let [mydict (new Hashtable)]
      (reduce (fn [counts x]
            (let [y (.toLowerCase x)]
              (if (.get mydict y)
            (.put mydict y (+ (.get mydict y) 1))
            (.put mydict y 1)))) coll) mydict))

이것은 약간의 컬렉션을 취하고 각각의 다른 것 (문자열의 단어)이 몇 번이나 재사용되는지를 반환하는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top