【问题标题】:Return list of instances from generic method从泛型方法返回实例列表
【发布时间】:2019-05-31 11:54:00
【问题描述】:

我需要在泛型方法中返回一个矩形的坐标列表。坐标是类“购物车”实例。

我尝试用 make-instance 返回它

(defclass line ()
  ((start :initarg :start :accessor line-start)
   (end   :initarg :end   :accessor line-end)))

(defmethod print-object ((lin line) stream)
  (format stream "[LINE ~s ~s]"
          (line-start lin) (line-end lin)))

(defclass cart ()
  ((x :initarg :x :reader cart-x)
   (y :initarg :y :reader cart-y)))

(defmethod print-object ((c cart) stream)
  (format stream "[CART x ~d y ~d]"
          (cart-x c) (cart-y c)))

(setq lin (make-instance 'line
             :start (make-instance 'cart :x 4 :y 3)
             :end (make-instance 'cart :x 7 :y 5)))

(defgeneric containing-rect (shape))

(defmethod containing-rect ((l line))
  (let ((x1 (cart-x (line-start l)))
        (y1 (cart-y (line-start l)))  
        (x2 (cart-x (line-end l)))
        (y2 (cart-y (line-end l))))
    (cond ((= x1 x2) 
           '((make-instance 'cart :x (1- x1) :y y1)
             (make-instance 'cart :x (1+ x1) :y y1)
             (make-instance 'cart :x (1- x2) :y y2)
             (make-instance 'cart :x (1+ x2) :y y2)))
          ((= y1 y2)
           '((make-instance 'cart :x x1 :y (1- y1))
             (make-instance 'cart :x x1 :y (1+ y1))
             (make-instance 'cart :x x2 :y (1- y2))
             (make-instance 'cart :x x2 :y (1+ y2))))
          (t 
           (rect '((make-instance 'cart :x x1 :y y1)
                   (make-instance 'cart :x x1 :y y2)
                   (make-instance 'cart :x x2 :y y2)
                   (make-instance 'cart :x x2 :y y1)))))))

(print (containing-rect lin))

我想make-instance 应该为某事分配一个实例

所以我得到了不正确的结果

((MAKE-INSTANCE 'CART :X X1 :Y Y1) (MAKE-INSTANCE 'CART :X X1 :Y Y2)
 (MAKE-INSTANCE 'CART :X X2 :Y Y2) (MAKE-INSTANCE 'CART :X X2 :Y Y1)) 

但我需要这样的输出

([CART x 4 y 3] [CART x 4 y 3] [CART x 4 y 3] [CART x 4 y 3])

【问题讨论】:

  • 为什么不调用lin变量line

标签: common-lisp evaluation quote


【解决方案1】:

如果你 quote 某事,它不会被评估。

这个:

'((make-instance 'cart :x (1- x1) :y y1)
  (make-instance 'cart :x (1+ x1) :y y1)
  (make-instance 'cart :x (1- x2) :y y2)
  (make-instance 'cart :x (1+ x2) :y y2))

是一个文字列表,由四个文字列表组成,每个列表都以符号MAKE-INSTANCE 开头,然后有一个列表(QUOTE CART) 等。这正是您看到的结果。 p>

您似乎想实际评估一下。最简单的事情就是这样做并列出一个清单:

(list (make-instance 'cart :x (1- x1) :y y1)
      (make-instance 'cart :x (1+ x1) :y y1)
      (make-instance 'cart :x (1- x2) :y y2)
      (make-instance 'cart :x (1+ x2) :y y2))

这与引用某事完全不同。

【讨论】:

    【解决方案2】:

    关于您的代码的一些额外提示。

    不是硬性规定,但访问器函数(它们是通用函数)通常仅以插槽命名,即 x 而不是 get-X(绝对是“坏”风格)或 object-X不是不好,仍然很常见)。

    (defclass line ()
     ((start :initarg :start :accessor start)
      (end   :initarg :end   :accessor end)))
    
    (defclass cart ()
     ((x :initarg :x :reader x)
      (y :initarg :y :reader y)))
    
    (defclass rect ()
      ((upper-left :initarg :upper-left :accessor upper-left)
       (bootom-right :initarg :bottom-right :accessor bottom-right)))
    

    我不知道你的要求是什么,所以我发明了一些;特别是,我将矩形表示为 2 个点(左上角和右下角)。

    构造函数

    拥有构造函数有助于获得简洁易读的代码:

    (defun cart (x y) 
      (make-instance 'cart :x x :y y))
    
    (defun line (start end) 
      (make-instance 'line :start start :end end))
    

    在矩形的情况下,首先对点进行排序,以便构建左上角和右下角的点。

    (defun sorted-coordinate (points coordinate)
      (sort (mapcar coordinate points) #'<))
    
    (defun rect (point-1 point-2)
      (let ((points (list point-1 point-2)))
        (destructuring-bind (low-x high-x) (sorted-coordinate points #'x)
          (destructuring-bind (low-y high-y) (sorted-coordinate points #'y)
            (make-instance 'rect
                           :upper-left (cart low-x high-y)
                           :bottom-right (cart high-x low-y))))))
    

     打印机方法

    您的代码几乎打印了 Lisp 表单,并且为了不增加复杂性,您实际上可以让打印机方法发出可以读回的代码以构建相同的数据。以下方法可读打印带有PRIN1 的对象,作为对先前定义的构造函数的调用:

    (defmethod print-object ((line line) stream)
      (prin1 `(line ,(start line) ,(end line)) stream))
    
    (defmethod print-object ((c cart) stream)
      (prin1 `(cart ,(x c) ,(y c)) stream))
    
    (defmethod print-object ((rect rect) stream)
      (prin1 `(rect ,(upper-left rect) ,(bottom-right rect)) stream))
    

    示例

    (defparameter *test-line*
      (line (cart 4 3) (cart 7 5)))
    

    然后,评估结果行给出:

    CL-USER> *TEST-LINE*
    => (LINE (CART 4 3) (CART 7 5))
    

    上面是一个值,由 REPL 打印,这正是用于构建它的表达式。

    矩形的边界

    通用函数要简单得多(但可能是错误的,因为矩形的处理方式不同):

    (defgeneric containing-rect (shape))
    
    (defmethod containing-rect ((line line))
      (rect (start line) (end line)))
    

    例如:

    CL-USER> (containing-rect *test-line*)
    => (RECT (CART 4 5) (CART 7 3))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      • 2014-10-16
      • 2016-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多