我想知道如何存储单个变量并对该变量具有特定的函数。我想知道是否有创建类的替代方案。
具体来说,我正在创建一个应用程序,在这个应用程序中,我存储一个时间值,该值表示从基本时间(例如,Jan 1, 2000, 00:00:00)经过的秒数。我想对这个值执行一些操作,比如将秒值转换为特定的时间或日期,或者将日期转换为特定的秒值。
我已经使用一个类完成了这个,但是它看起来很浪费。具体来说,每次访问经过秒数的存储值时,它看起来类似于(time-time time)
,其中time-time
是时间实例time
的访问器。
有没有更好的方法来设计这个,也许不需要类?
访问器名称
您可以在CLOS中以任何您喜欢的方式命名访问器。访问器函数可以称为seconds
:
CL-USER 23 > (defclass mytime ()
((seconds :accessor seconds :initarg :seconds)))
#<STANDARD-CLASS MYTIME 422015CDD3>
CL-USER 24 > (let ((mt (make-instance 'mytime :seconds 100)))
(values (seconds mt)
(truncate (seconds mt) 60)))
100
1
通过accessor函数更短地访问slot
Common Lisp也有一个形式WITH-ACCESSORS
。它允许我们在代码中使用符号而不是访问器形式——对于某个CLOS对象。在下面的示例中,我们可以使用secs
,它在代码中看起来像一个变量,但是Common Lisp将确保它实际上调用了访问器seconds
。我们可以写secs
而不是(seconds mt)
。因此,它有助于使封闭的代码更短。将下一个示例与上面的代码进行比较。
CL-USER 25 > (let ((mt (make-instance 'mytime :seconds 200)))
(with-accessors ((secs seconds))
mt
(values secs (truncate secs 60))))
200
3
SLOT-VALUE
CLOS也有WITH-SLOTS
用于通过插槽名称访问插槽,这里mytime
实例的seconds
插槽可以通过名称secs
访问:
CL-USER 26 > (let ((mt (make-instance 'mytime :seconds 200)))
(with-slots ((secs seconds))
mt
(values secs (truncate secs 60))))
200
3
如果你有一个类,它只是包装一个对象,并且该对象有一个已知的类型,那么你总是可以为该对象的类编写方法:
(defmethod time-as-unix-time ((tm integer))
(- tm (load-time-value (encode-universal-time 0 0 0 1 1 1970 0))))
例如。
当然,如果面向对象的狂热者发现你在做这种事情,他们会把你扔进一个充满钉子的坑里:毫无疑问,这违反了封装或其他一些邪教规则。
您可以在词法范围内尝试闭包,如下所示:
(let ((time (get-universal-time)))
(defun set-time(tm)
(setf time tm))
(defun get-time()
time)
(defun get-time-in-some-other-format()
;; calculate return value based on 'time'
)
)