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

欢迎!请查看关于页面以了解更多关于该怎样工作的信息。

0
编译器

嗨!
我的 Clojure 项目中有两个文件。
第一个(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 认为结果为 null),Clojure 将其解释为对函数的调用,执行带有 1 个参数的 nil。由于 nil 不是一个函数,它抛出一个异常。尽管我在 Clojure 1.11.1 中运行,但得到了一个稍微不同的错误消息。

修复方法是,在 cond 中的打印语句周围使用一个 `(do ...)` 循环。

  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])`。
...