我使用一种多方法来提供不同的功能,这取决于我的项目运行的"模式"(它是一个yadaapi服务器,应该能够在:dev
、:prod
等模式下运行(。
我使用mount/defstate
来提供一个关键字:
(defstate mode :start :dev)
当我使用(constantly mode)
进行调度时,会出现错误,但当我使用(fn [& _] mode)
进行调度时似乎可以正常工作。
这两种形式不一样吗?或者在评估它们的方式(或时间(上是否存在一些细微的差异?
在装载中,如果尚未启动状态,则它们的值为DerefableState
对象。
通过不断调用,您首先计算mode
的值,然后用该值调用constantly
函数。这意味着,当您调用constantly
的结果时,它将始终返回的参数为,尽管您已经更改了它。如果您在调用constantly
之前尚未启动状态,则它将存储DerefableObject
。
另一方面,对于(fn [& _] mode)
,每次调用函数时都要计算mode
var的值。如果你还没有开始你的状态,那么它也会返回一个DerefableState
,但如果你已经开始了,那么结果将是预期的关键字。
一个简单的解决方案是将调度函数也置于一种状态。
(defstate dispatch :start (constantly state))
我认为对于另一种解释,你可以使用副作用来突出区别
比较:
(def const-f (constantly (println "Hello!")))
Hello!
=> #'user/const-f
(def fn-f (fn [] (println "World!")))
=> #'user/fn-f
仅仅执行第一个def
就导致打印Hello!
,因为constantly
的主体立即被评估。然而,第二个def
不打印任何内容,因为fn
的主体没有被评估。
当打电话给他们时:
(const-f)
=> nil ; Prints nothing. Just evaluates to what println returned
(fn-f)
World! ; Prints now,
=> nil ; then returns what println evaluates to
constantly
不是宏,因此必须首先计算它的参数。然而,fn
是一个宏,因此它在计算参数之前运行。