2013-07-08 46 views
3

我想使用SQLKorma执行一些SQL语句。起初,我写了下面的代码:“For”失败,但“循环”工作

(let [sqls (-> (slurp "resources/database.sql") 
       (str/split #";") 
       butlast)] 
    (for [sql sqls] 
     (k/exec-raw sql))) 

但原因不明,这是行不通的。 for循环完全跳过。然而这工作:

(let [sqls (-> (slurp "resources/database.sql") 
       (str/split #";") 
       butlast)] 
    (loop [sqls sqls] 
    (if (not (empty? sqls)) 
     (do 
     (k/exec-raw (first sqls)) 
     (recur (rest sqls)))))) 

为什么会发生这种情况?为什么for循环失败?

+1

在Clojure'for'不是一个循环,它是列表理解。不要让这个名字欺骗你。 – ivant

回答

4

for创建一个惰性序列。只有当你实际使用它时,Clojure才会执行懒惰序列的每个元素。如果您只需要副作用,您应该强制执行延迟序列dorun

在你的情况我建议你使用map

(->> (str/split (slurp "resources/database.sql") 
       #";") 
    butlast 
    (map k/exec-raw) 
    dorun) 

doseqsee mtyaka's answer),而不是for

(doseq [sql (-> (slurp "resources/database.sql") 
       (str/split #";") 
       butlast)] 
    (k/exec-raw sql)) 

我喜欢map版本的更多,但是doseq工作的点点更快。

+1

地图很懒就像是; mapv不是懒惰 – noisesmith

+0

是的,这就是为什么在我的例子中有一个'dorun'。 –

+0

我根据mtyaka的回答添加了'doseq'示例。 –

8

for是懒惰的。改为使用doseq

(doseq [sql sqls] 
    (k/exec-raw sql))