3

我对以下代码有几个问题:

(import 
 '(java.awt Color Graphics Dimension)
 '(java.awt.image BufferedImage)
 '(javax.swing JPanel JFrame))

(def width 900)
(def height 600) 

(defn render
 [g]
 (let [img (new BufferedImage width height 
                 (. BufferedImage TYPE_INT_ARGB))
       bg (. img (getGraphics))]
   (doto bg
      (.setColor (. Color white))
      (.fillRect 0 0 (. img (getWidth)) (. img (getHeight)))
      (.setColor (. Color red))
      (.drawOval 200 200 (rand-int 100) (rand-int 50)))
   (. g (drawImage img 0 0 nil))
   (. bg (dispose))
   ))

(def panel (doto (proxy [JPanel] []
                        (paint [g] (render g)))
             (.setPreferredSize (new Dimension 
                                     width 
                                     height))))

(def frame (doto (new JFrame) (.add panel) .pack .show))

(def animator (agent nil))


(defn animation 
  [x]
  (send-off *agent* #'animation)
  (. panel (repaint))
  (. Thread (sleep 100)))

(send-off animator animation)
  1. 在动画功能中——为什么#'在发送动画之前使用?
  2. 为什么send-off动画功能开始时起作用?它不应该只是再次启动动画功能并且从不执​​行重绘和睡眠方法吗?
  3. 与原版相比,将动画函数编写为:

    (defn animation 
      [x]
      (. panel (repaint))
      (. Thread (sleep 100))
      (send-off *agent* animation))
    
4

2 回答 2

8

在动画功能中 - 为什么在发送动画之前使用#'?

展示 Clojure 的动态特性。

表单#'animation是 Var,Clojure 的可变引用类型之一。defn宏创建一个 Var 。为方便起见,调用引用函数的 Var 与调用函数本身相同。但是 Var 与函数不同,它可以改变!我们可以#'animation在 Clojure REPL 上重新定义并立即看到效果。

每次使用(send-off *agent* #'animation)强制 Clojure 查找 Var 的当前值。#'animation如果代码(send-off *agent* animation)改为使用,那么 Clojure 将只查找该值一次,并且在不停止循环的情况下无法更改动画函数。

于 2011-05-11T21:19:27.560 回答
3

1.这对我来说也有点不清楚,但似乎是 Rich 的设计决定。如果您注意到:

user=> (defn x [y] (+ y 2))
#'user/x
user=> ((var x) 3)
5

如果 var 位于函数/宏位置,它最终将解析为函数或宏。

2.这里要理解的一件重要的事情是代理模型。代理可以被认为是在单个可变单元格上操作的工人。该代理有一个工作队列(功能队列)要做。发送和发送添加工作到该队列。由于发送只是将工作添加到队列中,因此它会立即返回。由于代理仅按顺序执行功能,因此第一个动画调用必须在执行下一个动画调用之前完成。因此,无论先送行还是最后送行,您都能实现基本相同的目标。

3.两者之间应该没有明显的区别。

于 2011-05-11T15:12:36.647 回答