Clojure 2024 年状态调查 中分享您的想法!

欢迎!请参阅关于页面了解如何使用本站的一些信息。

0
编译器

嗨!
我的 Clojure 项目中有2个文件。
第一个(db.clj)从txt文件中读取数据并将其存储在向量列表中,第二个(menu.clj)显示包含多个选项的菜单。
我的条件是工作的:表格显示得如我预期,但是我最后遇到了一个奇怪的错误,导致我的应用停止运行。
详细信息
db.clj

(ns db)    
(defn load-data
  [filename]
  (with-open [rdr (io/reader filename)]
    ;; https://docs.clojure.org/clojure.core/doall
    (doall
      (for [line (line-seq rdr)
            :let [[id & data] (clojure.string/split line #"\|")]]
        [(Integer/parseInt id)
         data]))))

menu.clj

(ns menu
  (:require [db])
  )


(def customers (db/load-data "cust.txt"))
(def products (db/load-data "prod.txt"))

(def input_ 0) ; initialize input   

(defn menu
  []
  (if (not= input_ "6")
    (do
      (newline) ; insert a new line
      (println " ** MENU ** ") ; display menu
      (println "
1. Display Customer Table
2. Display Product Table
3. Display Sales Table
4. Total Sales for Customer
5. Total Count for Product
6. Exit")
      (println "Enter an option > ")
      (flush)
      (def input_ (read-line)) ; put the input in input_ variable
      (cond
        (= input_ "1") 
          ((println "Table of customers: ")
          ; run >> every item in a newline
          (run! println (db/load-data "cust.txt")))
        (= input_ "2") 
          ((println "Table of products: ")
          ; run >> every item in a newline
          (run! println (db/load-data "prod.txt")))
        :else (println "Option not handled!")
        )
      ;(println (str "The option entered is: \"" input_ "\""))
      (menu))
    (println "Goodbye!") ; If user prompts 6
    ))

控制台

    ** MENU ** 

1. Display Customer Table
2. Display Product Table
3. Display Sales Table
4. Total Sales for Customer
5. Total Count for Product
6. Exit
Enter an option > 
2
Table of products: 
[1 (shoes 14.96)]
[2 (milk 1.98)]
[3 (jam 2.99)]
[4 (gum 1.25)]
[5 (eggs 2.98)]
[6 (jacket 42.99)]
Syntax error (NullPointerException) compiling at (menu.clj:42:1).
null

Full report at:
/tmp/clojure-4521524603536338044.edn

谢谢!

1 个回答

+2

被选中
 
最佳答案
  1. 你应该检查并包含文件 /tmp/clojure-4521524603536338044.edn 中的堆栈跟踪(错误消息中包含文件路径)。

  2. 问题可能在于 cond 语句:

(cond
     (= input_ "1") 
     ((println "Table of customers: ")
     (run! println (load-data "cust.txt")))) 

如果 input_ 是 "1",然后执行语句 ((println "客户表:") (run! println (load-data "cust.txt")))》。如果我们逐步展开括号,那变成

(nil nil)

(println求值结果为nil), Clojure将其解释为函数调用,以1个参数执行nil。由于nil不是一个函数,它抛出了一个异常。不过我在Clojure 1.11.1中运行时得到了一个稍微不同的错误消息。

修复方法是给cond中的打印部分添加一个(do ...) loop

  1. 看起来你正在学习Clojure。作为一些建议,这种语言被设计成使用(let)代替(def input_ (readline)),使用recur代替对menu的递归调用。恭喜你找到了这里的cond,这是一个很好的函数。
by
谢谢!但是(do...)并没有解决问题。我仍然有相同的空指针错误...
by
你可能打错了。对我来说这个方法是有效的

    (ns menu
      (:require [db])
      )
    
    (def customers (db/load-data "cust.txt"))
    (def products (db/load-data "prod.txt"))
    
    (defn menu
      []
      (newline) ; 插入换行符
      (println " ** MENU ** ") ; 显示菜单
      (println "
    1. 显示客户表
    2. 显示产品表
    3. 显示销售表
    4. 客户总销售
    5. 产品总数
    6. 退出")
      (println "Enter an option > ")
      (flush)
      (let [input_ (read-line)] ; 将输入存入input_变量
        (cond
          (= input_ "1")
          (do (println "客户表: ")
              ;; 运行 >>> 在新行中显示每一项
              (run! println (db/load-data "cust.txt"))
              (recur))
    
          (= input_ "2")
          (do (println "产品表: ")
                                            ; 运行 >>> 在新行中显示每一项
              (run! println (db/load-data "prod.txt"))
              (recur))
    
          (= input_ "6")
          (println "再见!") ; 如果用户提出6
    
          :else
          (println "未处理的选项!"))))

当声明 `db` 命名空间时,还需要包含 `(:require [clojure.java.io :as io])`。
...