问题
user=> (def m (sorted-map 1 2))
#'user/m
user=> (map? m)
true
user=> (get m :type)
ClassCastException java.lang.Long cannot be cast to clojure.lang.Keyword
clojure.lang.Keyword.compareTo (Keyword.java:114)
It appears that sorted-map
has chosen a numerical comparison function, which won't compare with a keyword.
It would be nice to reason, "This thing supports IPersistentMap. So, I can call get
on it to find out if it's a kind of map that I know about without risk of throwing an exception." The docstring for get
says "Returns the value mapped to key, not-found or nil if key not present."
Is throwing an exception on key look-up a bug? More importantly, is there a safe, standard way to check if an arbitrary object is of a given "type" (defined by the value associated with its :type
key)?
回答1:
It would seem reasonable that keys to a sorted-map
should be comparable in some way, which is not the case with 1
and :type
, this is the cause of your exception.
Having said that I'd argue that you should be able to query a map with a key of any type and get nil
if the supplied key and keys in the map are not comparable.
You can solve the problem by supplying your own comparator via sorted-map-by
that does the required type checking.
回答2:
this is a thought-provoking question, i'm glad you asked it. after pondering, I would tend expect the same as was mentioned in the other answer -- i'd probably like a nil
to be returned, but maybe Rich has a philosophical reason for doing it this way instead.
as for the last part of your question: you can use type
. you can also use instance?
if you want to test for a known type. i guess the trick is the type is (almost always i believe) going to be the underlying Java class
user=> (type foo)
clojure.lang.PersistentTreeMap
user=> (instance? clojure.lang.PersistentTreeMap foo)
true
Edit: per discussion below, I'm putting some additional example code here (easier to read than in comments). this will allow arbitrary metadata to be attached to the data structure:
user=> (def foo (sorted-map 1 2))
#'user/foo
user=> (def foo-enhanced (with-meta foo {:type :integer-keys}))
#'user/foo-enhanced
user=> foo-enhanced
{1 2}
user=> (meta foo-enhanced)
{:type :integer-keys}
来源:https://stackoverflow.com/questions/37410580/sorted-map-throws-exception-on-failed-key-look-up