2

在理解类中处理文件访问的 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)))

在“构造函数”(即初始化实例)中,我打开文件就像我的 c++ 习惯用法一样。然后我可以访问数据,并且可以像以前一样解析数据。但是,有人告诉我,使用“析构函数”或(finalize)方法来关闭文件不是惯用的 CLOS 来处理这种我需要文件存在的情况,以便我可以在我的数据文件之外访问它方法。

我将定义一个加载数据文件的函数,然后对其数据执行一系列分析,然后希望将其关闭。有什么方法可以做到这一点?(我假设宏或某种类型的闭包可以在这里工作,但我对 lisp 方式不够熟悉来决定需要什么或如何实现它)。

4

2 回答 2

6

一种选择是将流作为插槽而不是文件名,然后使用 WITH-OPEN-FILE 对其进行范围:

(with-open-file (stream file)
  (let ((foo (make-instance 'foo :stream stream)))
    (frob foo)
    (...other processing of foo...)))

然后您的流将自动关闭。

于 2009-11-04T18:48:23.187 回答
3

我想我会倾向于只创建类来存储完整的权威数据(你称之为 DataStruct?)。

你真的不需要一个特殊的类来“加载+存储另一个类”。另外,这种方式有一个不言而喻的不变量,即 my_data 将 my_file 的数据保持到当前的搜索位置,这对我来说似乎有点奇怪。

换句话说:Foo是做什么的?给定一个文件名,它会加载数据,并给你一个 DataStruct。这对我来说听起来像是一个功能。如果您需要能够在线程中运行它,或者在加载记录之间触发事件,那么在 C++ 中使用类是很自然的方式,但在 Lisp 中您不需要类来处理这些事情。

另外,请记住,您无需使用 DEFCLASS 即可在 CLOS 中使用泛型方法。

我不知道你的数据结构是什么,但在类似的情况下,我制作了一个解析一个块的函数,它接受一个流并返回一个记录,然后在一个循环中创建一个完整的 Foo 实例-打开文件。如果在 with-open-file 扩展的范围之外永远不需要流,则无需担心关闭它。

于 2009-11-04T19:57:45.030 回答