So, you have to deal with a map, but you can't be sure whether or not you have a value for a given key.
The easiest, and probably the most known is to use the get function (that accepts optionally a third argument which is the fallback value).
(def a-qb {:name "Josh"
:surname "McCown"
:team "New York Jets"})
(def another-qb {:name "Robert"
:surname "Griffin III"})
(get a-qb :team) ; => "New York Jets"
(get another-qb :team) ; => nil
(get another-qb :team "Free Agent") ; => "Free Agent"
Another way is to use the keyword as a function or even the map as a function.
(:team a-qb) ; => "New York Jets"
(:team another-qb) ; => nil
(a-qb :team) ; => "New York Jets"
(another-qb :team) ; => nil
I've learned that you can also specify a second argument to these cases, and if the value is not found, it will return this second argument.
(:team a-qb "Free Agent") ; => "New York Jets"
(:team another-qb "Free Agent") ; => "Free Agent"
(a-qb :team "Free Agent") ; => "New York Jets"
(another-qb :team "Free Agent") ; => "Free Agent"
But what if you want to raise an exception if it does not exists?
(a-qb :team (throw (Exception. )))
(a-qb :team (throw (Exception. )))
If you call it this way, it will evaluate all parameters before the function is called (because it is a function), raising an exception regardless if the key-value pair exists or not on the map. A way to workaround this it is to use an or
.
(or (a-qb :team)
(throw (Exception. ))
Because the or
is implemented as a macro, it will only evaluate the second sexp (throw ...)
unless the first sexp is falsy (nil or false) and thus raising an exception only on this case.
Top comments (2)
This example should return "Free Agent" and not nil
checked in the REPL:
Thanks, I've fixed them :)