10

最近我正在编写一个小 CLI 脚本,它需要从控制台重复读取日期(要读取的日期数是计算出来的,每次可能不同)。示例 Ruby 代码为您提供思路:

dates = x.times.collect { print "Enter date: "; Date.parse(gets.chomp) }

只是为了它,我在 Clojure 中编写了脚本,最后使用了一些相当丑陋的代码swap!loop...recur. 我想知道在 Clojure 中实现预期效果的最干净的方法是什么。(Clojure 确实有dotimes,但它不保留从评估主体返回的值......正如强调纯函数式编程的语言所预期的那样。)

4

3 回答 3

10

到达文件末尾时,read-line 返回 nil。在您按下 CTRL-d (Windows 上的 CTRL-z)时的控制台上。

您可以使用此代码来利用这一点:

(doseq [line (repeatedly read-line) :while line]
    (do-something-with line))

如果您必须阅读固定数量的行,您可以使用:

(repeatedly n read-line)
于 2012-07-14T16:10:06.117 回答
9

如果您的目标是最终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: ")
于 2012-07-14T22:33:48.720 回答
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
于 2012-07-14T13:46:37.953 回答