最近我写了一个小的CLI脚本,需要重复从控制台读取日期(计算读取的日期数量,每次都可能不同)。示例Ruby代码为您提供了想法:
dates = x.times.collect { print "Enter date: "; Date.parse(gets.chomp) }
只是为了它,我在Clojure中编写了脚本,并使用swap!
和loop...recur
使用了一些相当丑陋的代码。我想知道在Clojure中达到预期效果最干净的方法是什么。 (Clojure确实有dotimes
,但它没有保留从评估正文返回的值......正如强调纯函数式编程的语言所期望的那样。)
答案 0 :(得分:10)
读取行返回nil。在按CTRL-d (Windows上的CTRL-z)时的控制台上。
您可以使用此代码来利用此功能:
(doseq [line (repeatedly read-line) :while line]
(do-something-with line))
如果您必须阅读固定数量的行,您可以使用:
(repeatedly n read-line)
答案 1 :(得分:8)
如果您的目标是以用户输入的一系列x
日期结束,那么:
(for [line (repeatedly x read-line)] (DateFormat/parse line))
或使用map
:
(map DateFormat/parse (repeatedly x read-line))
谨防Clojure中的延迟序列:系统会要求用户根据需要输入更多日期。如果您的目标是让用户一次输入所有日期(例如在启动时),请使用doall
:
(map DateFormat/parse (doall (repeatedly x read-line)))
这将一次读取所有日期,但仍会懒散地解析它们,因此日期格式验证可能会在程序中稍后失败。您可以将doall
一级移动到即时解析:
(doall (map DateFormat/parse (repeatedly x read-line)))
你可以使用辅助函数来读取带有提示符的行:
(defn read-line-with-prompt [prompt]
(print prompt)
(read-line))
然后将read-line
替换为:
#(read-line-with-prompt "Enter date: ")
或
(partial read-line-with-prompt "Enter date: ")
答案 2 :(得分:4)
您可以这样做:
(defn read-dates [n]
(doall (for [_ (range n)] (java.util.Date/parse (read-line)))))
(def my-dates (read-dates 5)) ;Read 5 dates from console