в понятиях времени, когда тело оценивается, оба они вызывают тело ровно один раз, но эта форма касается не только времени выполнения, но и лени / рвения. Макрос delay
оборачивает тело в специальный ссылочный объект и откладывает его выполнение до первой разыменования:
user> (let [x (delay 100)]
(println x)
(Thread/sleep 100)
(println "woke up")
(println x)
(println @x)
(println x)
@x)
;;=> #delay[{:status :pending, :val nil} 0x273336d4]
;; woke up
;; #delay[{:status :pending, :val nil} 0x273336d4]
;; 100
;; #delay[{:status :ready, :val 100} 0x273336d4]
;; 100
defonce
само по себе стремится, возвращая отложенный блок сразу, но неего выполнение.
, что означает, что datasource
устанавливается в инкапсулированный ленивый блок, который должен выполняться именно тогда, когда коду сначала нужно получить источник данных (вызывая deref
или @
),и defonce
здесь, чтобы запретить переопределение этого вар. Я бы назвал это «ленивый синглтон».
user> (defonce value
(do (println "DEFINING!")
(delay
(println "EVALUATING!")
101)))
;;=> DEFINING!
#'user/value
user> value
#<Delay@b1388c1a: :not-delivered>
user> @value
;;=> EVALUATING!
101
user> value
#<Delay@1ed9ec81: 101>
;; `delay` caches value (doesn't print again)
user> @value
101