gpt4 book ai didi

clojure - 如何正确处理 with-open 而不会在使用流之前关闭流?

转载 作者:行者123 更新时间:2023-12-02 23:07:39 25 4
gpt4 key购买 nike

我正在编写我的第一个 Clojure 程序。

我正在使用 clojure.data.csv 来处理 csv 文件。我的文件可能很大,所以我确实想利用懒惰。用于演示我的问题的 MWE 代码如下所示。

当我执行加载数据函数时,我得到“IOException Stream closeed”,因此我很清楚惰性流在消费点之前被关闭。

我查看了 data.csv ( https://github.com/clojure/data.csv ) 的文档,可以看到防止流在使用之前关闭的一种方法是将流打开移动到使用流的调用堆栈。据我了解,这就是我在下面所做的,因为 (take 5) 在 with-open 的范围内。显然,我有一个概念上的差距。非常感谢任何帮助!

(ns data-load.core
(:gen-class)
(:require [clojure.data.csv :as csv]
[clojure.java.io :as io]))

(defn load-data [from to]
(with-open [reader (io/reader from)
writer (io/writer to)]
(->> (csv/read-csv reader)
(take 5))))

最佳答案

正如您所说,您从 load-data 返回的内容是一个惰性序列,当它被消耗时,你已经离开了 with-open 的范围。您只需要在返回之前强制实现惰性序列即可。

As far as I understand it, this is what I have done below since (take 5) is within the confines of with-open.

在范围之内,但是take还返回一个惰性序列!它只是将一个惰性序列包装在另一个序列中,直到 with-open 之后才会实现。范围。来自 clojure.data.csv 示例:

(defn sum-second-column [filename]
(with-open [reader (io/reader filename)]
(->> (read-column reader 1)
(drop 1)
(map #(Double/parseDouble %))
(reduce + 0)))) ;; this is the only non-lazy operation

这里重要的观察是最终操作是 reduce这将消耗惰性序列。如果你拿了reduce out 并尝试从函数外部使用生成的序列,您会得到相同的“流关闭”异常。

实现此目的的一种方法是将序列转换为向量 vec ,或使用doall这也将迫使它被实现:

(defn load-data [from]
(with-open [reader (io/reader from)]
(->> (csv/read-csv reader)
(take 5)
;; other intermediate steps go here
(doall))))

My file is potentially large and so I do want to exploit laziness.

您需要一种方法来在流关闭之前完成所有工作,以便您可以向 load-data 提供一个函数对 CSV 的每一行执行的函数:

(defn load-data [from f]
(with-open [reader (io/reader from)]
(doall (map f (csv/read-csv reader)))))

例如,将行值连接成字符串:

(load-data (io/resource "input.txt")
(partial apply str))
=> ("abc" "efg")

关于clojure - 如何正确处理 with-open 而不会在使用流之前关闭流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48723378/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com