2013-03-02 32 views
0

我想写这样的事情(不工作):如何使用递增的id编写clojure工厂函数?

(defn new-connection [] 
    (let [c (atom 0)] 
    {:id #(swap! c inc) 
    :writebuf (ByteBuffer/allocate 8096) 
    :readbuf (ByteBuffer/allocate 8096)})) 

,这样我可以得到逐步id'd与(新连接)的地图,我需要单独定义计数器或有一种方法可以用这个函数内联它吗?

+0

取决于有多少价值,你放在引用透明? – 2013-03-02 01:46:53

+0

是否指在他编辑下面的mobyte的评论,关于'隐藏'柜台? – georgek 2013-03-02 03:01:40

+0

当涉及对象的计数时,您能期待引用透明吗?我怀疑。 – 2013-03-04 04:26:13

回答

1

您可以使用closure机制,以 “内联” 计数器:

(let [c (atom 0)] 
    (defn new-connection [] 
    {:id (swap! c inc) 
    :writebuf :ByteBuffer 
    :readbuf :ByteBuffer}) 
    (defn get-counter [] 
    @c)) 

(get-counter) 
=> 0 

(new-connection) 
=> {:id 1, :writebuf :ByteBuffer, :readbuf :ByteBuffer} 

(new-connection) 
=> {:id 2, :writebuf :ByteBuffer, :readbuf :ByteBuffer} 

(get-counter) 
=> 2 

或者,如果你需要控制计数器开始值:

(defn create-connection-fn [init-counter-value] 
    (let [c (atom init-counter-value)] 
    (fn [] 
     {:id (swap! c inc) 
     :writebuf :ByteBuffer 
     :readbuf :ByteBuffer}))) 

(def new-connection (create-connection-fn 10)) 

(new-connection) 
=> {:id 11, :writebuf :ByteBuffer, :readbuf :ByteBuffer} 

(new-connection) 
=> {:id 12, :writebuf :ByteBuffer, :readbuf :ByteBuffer} 

编辑。如果没有理由“隐藏”它,我建议你将计数器定义为分隔变量。

+0

谢谢你的答案。有一个问题,我已经读过,在函数中定义变量并不是一个好主意(比如(defn ...(def ..)))。这是否适用于像上面那样定义函数内的函数? – georgek 2013-03-02 03:13:29

+3

@georgek编号'let' over'defn'不是一个常见的clojure结构(人们似乎不喜欢它,尽管我自己喜欢它),但是它没有任何概念上的错误。相反,def内的def确实存在问题。 – amalloy 2013-03-02 03:44:03

+0

当var在函数之外(并且可能会显式传递给它)时,控制函数的行为会更容易。那么使用任何可以计数并返回下一个值的东西都会更容易。在let-over-def(n)的情况下,它只是'atom'。反对使用let-over-def的一个更重要的原因是,在柜台上引入新功能很难 - 它们必须成为“let”范围的一部分。由于我们使用函数来组合函数(而不是命名空间),我的直觉感受告诉我将计数器定义为函数外的变量。 – 2013-03-04 04:34:47

2

这是一个非常普遍的问题,有一个计数器。如果你分解了一些东西,你会发现你需要三件事:1)创建新计数器的东西2)连接计数器3)新的连接函数接受id作为参数,而不是调用计数器本身,因为它使得这个函数更一般。

(defn new-counter [] 
    (partial apply swap! (atom 0) inc [])) 

(def connection-counter (new-counter)) 

(defn new-connection [id] 
    {:id id 
    :writebuf (ByteBuffer/allocate 8096) 
    :readbuf (ByteBuffer/allocate 8096)}) 

现在你可以使用它像:

(new-connection (connection-counter))