我遇到了解CLOS处理类中文件访问方式的问题。在c ++中,我可以这样做:
class Foo {
Foo (string filename); // opens the file (my_file) requested by the filename
~Foo (); // close the file
FILE * my_file; // a persistent file-handle
DataStruct my_data; // some data
void ParseData (); // will perform some function on the file and populate my_data
DataStruct * GetData () { return &my_data; } // accessor to the data
};
我想指出的是PraseData()将被多次调用,每次从文件中解析出一个新的数据块,my_data就会被更改。
我正在尝试在CLOS中执行相同的技巧 - 创建所有通用方法来解析数据,加载文件,读取标题等,以及我所拥有的类定义:
(defclass data-file ()
((filename :initarg :filename :accessor filename)
(file :accessor file)
(frame :accessor frame)))
在“构造函数”(即initialize-instance)中,我打开文件就像我的c ++习语一样。然后我可以访问数据,我可以像以前一样解析数据。但是,我被告知使用“析构函数”或(finalize)方法来关闭文件不是惯用的CLOS来处理这种情况,我需要文件在那里,所以我可以在我的数据文件之外访问它方法
我将定义一个加载数据文件的函数,然后对其数据执行一系列分析,然后希望将其关闭。这是怎么回事? (我假设一个宏或某种类型的闭包可以在这里工作,但我不熟悉lisp方式来决定需要什么或如何实现它。)
答案 0 :(得分:6)
一个选项是将流作为插槽而不是文件名,然后使用WITH-OPEN-FILE将其作为范围:
(with-open-file (stream file)
(let ((foo (make-instance 'foo :stream stream)))
(frob foo)
(...other processing of foo...)))
然后您的信息流将自动关闭。
答案 1 :(得分:3)
我想我会倾向于只创建类来存储完整的权威数据(你称之为DataStruct?)。
你真的不需要一个特殊的类来“加载+存储另一个类”。另外,这种方式具有未说出的不变量,即my_data将my_file的数据保存到当前的搜索位置,这对我来说似乎有点奇怪。
换句话说:Foo做什么?给定文件名,它会加载数据,并为您提供DataStruct。这对我来说听起来像是一种功能。如果你需要能够在一个线程中运行它,或者在加载记录之间触发事件,那么类是在C ++中执行它的自然方式,但是你不需要在Lisp中为这些东西创建一个类。
另外,请记住,您不需要使用DEFCLASS来在CLOS中使用泛型方法。
我不知道你的数据的结构是什么,但在类似的情况下,我做了一个parse-one-chunk函数,它接受一个流并返回一条记录,然后在一个循环中创建一个完整的Foo实例在一个打开文件中。如果在with-open-file扩展的范围之外永远不需要流,您永远不必担心关闭它。