在if-else中执行多个语句而不使用nullpointer异常

ech*_*hox 41 clojure

我正在尝试深入研究clojure和函数式编程.

在我的代码的某些时候,我有一个(def server (spawn-server)).现在我想要一个REPL的短函数来检查这个套接字的状态.

这就是我现在所拥有的:

(defn status []
  (if server 
    (
      (println "server is up and running")
      (println "connections:" (connection-count server)) 
     )    
    (println "server is down")))
Run Code Online (Sandbox Code Playgroud)

如果服务器是nil,一切正常,但如果服务器正在运行,这是REPL上的输出:

=> (status)
server is up and running
connections: 0
#<CompilerException java.lang.NullPointerException (NO_SOURCE_FILE:0)>
Run Code Online (Sandbox Code Playgroud)

我不确定我是否看到了问题,但我无法弄清楚这应该如何工作:-)我在这里有这样的:

((println "foo")(println "foo"))
Run Code Online (Sandbox Code Playgroud)

哪个会被评估到(nil nil)NullPointerException的结果?

通常我不会使用外括号,但如何为if条件创建某种"块"语句.如果我不使用它们,第二个println将被用作其他.

什么是有效的是使用let作为某种"块" - 陈述:

(let [] 
  (println "server is up and running"),
  (println "connections:" (connection-count server)) )
Run Code Online (Sandbox Code Playgroud)

但我不确定这是否是"正确"的解决方案?

dan*_*lei 61

用途do:

(defn status []
  (if server 
    (do
      (println "server is up and running")
      (println "connections:" (connection-count server)))    
    (println "server is down")))
Run Code Online (Sandbox Code Playgroud)

通常,在Lisps中,您不能只添加用于分组的parens.

((println "foo") (println "foo"))
Run Code Online (Sandbox Code Playgroud)

这里,(println "foo")将尝试调用第一个的返回值(作为函数),将第二个的返回值作为参数.这些都是非常基本的评估规则,因此我建议您阅读一些关于Clojure或Lisps的介绍性书籍或文档.

来自Clojure主页评估部分:

非空列表被视为对特殊表单,宏或函数的调用.调用具有表单(运算符操作数*).

宏或特殊形式可能会"破坏"这一规则.

  • 来晚了一点,但是要具体解释一下空指针异常,是因为第一个 println 返回 nil。`if` 后面的括号表示“将此列表中的第一个元素作为函数求值”。因为第一个元素的计算结果为 nil,所以它会抛出异常。不是那么明显,但是 Clojure 中的空指针异常通常是因为您试图将 nil 作为函数执行。 (3认同)
  • @matanster 我不太了解原因,但我同意 Clojure 的错误消息不是最好的。 (2认同)