【问题标题】:Run two commands in a row after an if statement in Clojure在 Clojure 中的 if 语句之后连续运行两个命令
【发布时间】:2021-12-19 06:02:22
【问题描述】:

为什么下面的 Clojure 程序会抛出 NullPointerException?

user=> (defn x []  
       "Do two things if the expression is true."
       (if true ((println "first expr") (println "second expr")) false))

user=> (x)
first expr
java.lang.NullPointerException (NO_SOURCE_FILE:0)
second expr

这是我实际用例的简化版本,我想在返回映射之前执行三个语句(从数据库中提取值) - {:status 200, :body "Hello World"} 在分支内。

【问题讨论】:

标签: clojure


【解决方案1】:

它试图将第一个 println 的结果作为一个函数来调用第二个 println 函数。

您需要do

(defn x []  
   "Do two things if the expression is true."
   (if true (do (println "first expr") (println "second expr")) false))

(x)

do 特殊形式(CL 中的 progn,Scheme 中的开始)按顺序执行其每个参数并返回最后一个参数的结果。

【讨论】:

  • 一般来说是的。一些形式可能暗示它(例如,Scheme cond 暗示它,但我不认为 Clojure 的版本会暗示它,因为它的参数不在列表中)。 ((foo ...) (bar ...)) 通常意味着获取 foo 的结果并将其用作函数来调用其余参数。
  • 那么这是否意味着do 将按顺序执行语句? (它会假设它们有副作用)?
  • do 确实会按顺序执行其语句。
【解决方案2】:

如果 nil 在 else 情况下可以作为返回值,请考虑使用具有隐式 do 块的 when

(defn x []  
  "Do two things if the expression is true."
  (when true
    (println "first expr") 
    (println "second expr")))

【讨论】:

    【解决方案3】:

    这在您的特定情况下并不重要,但要知道 (do ...) 将在其自己的类加载器中加载每个表单和一个空的 let 表单 (let [] ...) 之间的区别,它在单个类加载器中评估整个表单。

    【讨论】:

    • 在自己的类加载器中加载每个表单与以其他方式加载的实际区别是什么?也许我不明白类加载器的含义。
    • 一个例子,你正在编写一个宏,它定义了一个自定义的 deftype 和多个类。作为优化,您希望使用相同的类加载器,以便创建更少的类加载器实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 2021-04-24
    相关资源
    最近更新 更多