2014-02-20 2 views
5

В Java я обычно делаю это,Clojure: несколько привязок Пусть

MyObject o1 = new MyObject(); 
o1.doSomething(); 
MyObject o2 = new MyObject(); 
o2.doWith(o1); 
MyObject o3 = new MyObject(); 
o3.doWithBoth(o1, o2); 

В Clojure, если я использую пусть привязок, он может выглядеть,

(let [o1 (create-obj)] 
    (.doSomething o1) 
    (let [o2 (create-obj)] 
    (.doWith o2 o1) 
    (let [o3 (create-obj)] 
     (.doWithBoth o3 o1 o2)))) 

Код выращивает вправо которая является уродливой и трудно поддерживать. Есть лучший способ сделать это?

ответ

10
(let [o1 (doto (create-obj) (.doSomething)) 
     o2 (doto (create-obj) (.doWith o1)) 
     o3 (doto (create-obj) (.doWithBoth o1 o2))] 
    ...) 

Для получения более подробной информации см. (doc doto).

(Update :) Это работает, потому что в каждом случае это вновь созданный объект, на который вы вызываете метод. Если вместо этого вы хотели бы вызвать функцию/метод с вновь созданным объектом, переданным в позиции аргумента, отличной от первой, вам, вероятно, лучше всего понравится трюк _, описанный шумоподавителем, хотя вы можете использовать doto с as->. Последнее имеет преимущество, заключающееся в том, что вы не вводите неиспользуемый локальный объект, который не будет очищен (последний раз, когда я проверил Clojure, только очищенные местные жители, на которые фактически ссылались в следующем коде), но это, конечно, не имеет значения, если вы звоните void -returning методы побочного эффекта.

+0

Что делает as-> do ?? Попробовал это сделать, но ничего не смог найти ... –

+0

Он преобразует '(as-> expr sym form1 form2 ...)' in '(let [sym expr sym form1 sym form2 ...] sym)' , См. '(Doc as ->)' в REPL (> = 1.5.0) или следуйте [этой ссылке] (http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/ as->), чтобы увидеть то же самое на странице API Clojure. (Я не смог найти стабильную ссылку на API 1.5.x, поэтому вместо ссылки на «текущий» я ссылаюсь.) –

+0

Чтобы быть понятным, вы должны использовать 'as->' inside 'doto':' (doto 1 (as-> foo (+ foo 2) (* foo 3) (println foo))) 'печатает 9 и возвращает 1. –

3

Стандартная идиома заключается в использовании _ в качестве связывания связывания для строк, оцененных для побочных эффектов.

(let [o1 (create-obj) 
     _ (.doSomething o1) 
     o2 (create-obj) 
     _ (.doWith o2 o1) 
     o3 (create-obj)] 
    (.doWithBoth o3 o1 o2)) 
3

Следующее (мое) решение жизнеспособно, но с плохим вкусом. Метод .dosomething & c не вызывает сомнений в отношении объектов, к которым они применяются. Так что мы делаем, строим объект, привязывая его к локальному имени, а затем мутируем его за кулисами. Eugh!

Ответ Michal Marczyck предпочтительнее, потому что doto возвращает мутированный объект, который затем привязан к локальному имени и никогда не мутирует после этого.

Мы не можем ожидать, что Java-взаимодействие будет соответствовать иконам Clojure, но мы должны попытаться отметить нарушения, как это делает doto.


let крепления сделаны слева направо. Таким образом, вы можете сделать выше, с одним из них:

(let [o1 (create-obj) 
     _ (.doSomething o1) 
     o2 (create-obj) 
     _ (.doWith o2 o1) 
     o3 (create-obj)] 
     (.doWithBoth o3 o1 o2)) 

Здесь мы связываем _ дважды. Это условное имя для игнорируемого привязки. Предположительно, .doSomething, .doWith и .doWithBoth выполнены для побочных эффектов.

Смежные вопросы