Clojure PersistentArrayMap传0参数ArityException报错排查
问题场景
使用clojure.core.memoize对数据库调用结果做缓存,初始缓存定义代码:
(def get-user-profile-cached (memo/memo (get-user-profile)))
其中get-user-profile执行后返回map类型结果。
后续在业务函数的let块中调用缓存方法,代码如下:
(defn get-user-from-token [token] (let [user (get-user-profile-cached) id (:id user)] ...))
执行代码时抛出异常:clojure.lang.ArityException: Wrong number of args (0) passed to: clojure.lang.PersistentArrayMap
问题根因
两处写法错误直接导致了这个异常:
- 定义缓存时错误地提前执行了原函数。
(memo/memo (get-user-profile))这行代码会立刻执行get-user-profile,拿到它返回的map对象,再把这个map传给memo/memo。而memo/memo的入参要求是函数类型,传入普通map后,最终get-user-profile-cached绑定的值根本不是带缓存能力的包装函数,就是get-user-profile第一次执行返回的那个map。 - 调用时把map当无参函数执行。Clojure中PersistentArrayMap虽然本身支持作为函数调用,但调用规则是必须传入要查找的key作为参数(比如
(some-map :id)等价于(:id some-map)),写(get-user-profile-cached)相当于给map传了0个参数调用,完全不符合调用约定,自然抛出参数数量不匹配的错误。
修正方法
定义缓存时不要给get-user-profile加括号(加括号代表执行函数,不加代表传递函数本身),正确写法:
(def get-user-profile-cached (memo/memo get-user-profile))
如果get-user-profile需要接收查询参数(比如用户ID、过滤条件),调用缓存函数时正常传入对应参数即可,memoize会自动按参数组合缓存对应结果。如果是无参函数,修正定义后原有调用逻辑不需要改动就能正常运行。
内容的提问来源于stack exchange,提问作者duplic8
相关产品推荐
相关产品推荐

