简体   繁体   English

如何用core.async通道模拟Rx的`withLatestFrom`?

[英]How to model Rx's `withLatestFrom` with core.async channels?

For example given a channel with operations and another channel with data, how to write a go block that will apply the operation on whatever was the last value on the data channel? 例如,给定一个带有操作的通道和另一个带有数据的通道,如何编写一个go块,它将对数据通道上的最后一个值应用该操作?

(go-loop []
  (let [op (<! op-ch)
        data (<! data-ch)]
    (put! result-ch (op data))))

Obviously that doesn't work because it would require both channels to have the same frequency. 显然这不起作用,因为它需要两个通道具有相同的频率。

(see http://rxmarbles.com/#withLatestFrom ) (见http://rxmarbles.com/#withLatestFrom

Using alts! alts! you could accomplish what you want. 你可以完成你想要的。

The with-latest-from shown below implements the same behavior found in the withLatestFrom from RxJS (I think :P). 下面显示的with-latest-from实现了与withLatestFrom的withLatestFrom相同的行为(我认为:P)。

(require '[clojure.core.async :as async])

(def op-ch (async/chan))
(def data-ch (async/chan))

(defn with-latest-from [chs f]
  (let [result-ch (async/chan)
        latest    (vec (repeat (count chs) nil))
        index     (into {} (map vector chs (range)))]
    (async/go-loop [latest latest]
      (let [[value ch] (async/alts! chs)
            latest     (assoc latest (index ch) value)]
        (when-not (some nil? latest)
          (async/put! result-ch (apply f latest)))
        (when value (recur latest))))
    result-ch))

(def result-ch (with-latest-from [op-ch data-ch] str))

(async/go-loop []
  (prn (async/<! result-ch))
  (recur))

(async/put! op-ch :+)
;= true
(async/put! data-ch 1)
;= true
; ":+1"
(async/put! data-ch 2)
;= true
; ":+2"
(async/put! op-ch :-)
;= true
; ":-2"

There's an :priority true option for the alts! 有一个:priority true选择alts! .

An expression which always returns the latest seen value in some channel would look something like this: 总是返回某个通道中最新看到的值的表达式看起来像这样:

(def in-chan (chan))

(def mem (chan))

(go (let [[ch value] (alts! [in-chan mem] :priority true)]
    (take! mem)      ;; clear mem (take! is non-blocking)
    (>! mem value)   ;; put the new (or old) value in the mem
    value            ;; return a chan with the value in

It's untested, it's probably not efficient (a volatile variable is probably better). 它未经测试,可能效率不高( volatile变量可能更好)。 The go -block returns a channel with only the value, but the idea could be expanded to some "memoized" channel. go -block返回一个只有值的通道,但这个想法可以扩展到一些“memoized”通道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM