Разница между использованием и потребностью

155

Кто-нибудь может объяснить разницу между useи require, как при непосредственном использовании, так и как :useи :requireв nsмакросе?

Jegschemesch
источник
2
См. Также stackoverflow.com/questions/10358149/… относительно макроса ns; в clojure 1.4 предлагается использовать: требовать по предпочтению: use
Korny

Ответы:

101

requireзагружает библиотеки (которые еще не загружены), useделает то же самое, плюс к ним относится их пространство имен clojure.core/refer(так что вы также можете использовать и :excludeт.д., как с clojure.core/refer). Оба рекомендуются для использования, nsа не напрямую.

Алекс Мартелли
источник
3
Если мне потребуется lib foo, то чтобы использовать bar в foo, мне придется каждый раз писать foo / bar, верно? Почему вы хотите загрузить библиотеку в ns, но не ссылаться на нее в ns? Я думаю, вы можете быть обеспокоены столкновениями, и вы не хотите беспокоиться о необходимости их примирить, верно?
Jegschemesch
12
отсутствие необходимости согласовывать коллизии - это хороший момент, и в целом существует стиль программирования, который гласит: «Пространства имен - это замечательная идея, у нас их должно быть больше» (из «Дзэн Python») - например, этот стиль рекомендует не используя "использование пространства имен foo;" в C ++, чтобы читатели и сопровождающие кода не беспокоились «откуда взялась эта панель», а вместо этого увидели более явный foo :: bar. require (vs use) поддерживает этот стиль "явных пространств имен".
Алекс Мартелли
2
Алекс дает хороший, но устаревший ответ. Как @overthink указывает ниже, после того, как этот ответ был дан, идиоматическая clojure рекомендует требовать чрезмерного использования. см .: dev.clojure.org/jira/browse/CLJ-879
Фил Купер
Несмотря на то, что это принятый и получивший наибольшее количество голосов ответ, он устарел и представляет собой устаревшее мнение. Лучший ответ: @rzv: stackoverflow.com/a/16429572/172272
Дидье А.
65

Идиоматично включать внешние функции с requireи refer. Вы избегаете конфликтов пространства имен, вы включаете только те функции, которые вы фактически используете / нуждаетесь, и вы явно объявляете местоположение каждой функции:

(ns project.core
    (:require [ring.middleware.reload :refer [wrap-reload]]))

Мне не нужно вызывать эту функцию путем добавления префикса к ее пространству имен:

(wrap-reload) ; works

Если вы не используете, referвам нужно добавить префикс к пространству имен:

(ring.middleware.reload/wrap-reload) ; works if you don't use refer in your require

Если вы выбираете useвместо этого (в значительной степени) всегда используйте only:

(ns project.core
    (:use [ring.middleware.reload :only [wrap-reload]]))

В противном случае вы включаете все, что делает это неоправданно большой операцией и очень запутанным для других программистов, чтобы найти, где живут функции.

Кроме того, я настоятельно рекомендую этот блог в качестве ресурса для получения дополнительной информации о пространствах имен Clojure.

RZV
источник
Знаете ли вы, есть ли разница в конце между (:use foo :only [bar])и (:require foo :refer [bar])? Кажется странным иметь два способа сделать это.
думаю,
10
Похоже, stackoverflow.com/a/10370672/69689 отвечает на мой вопрос. Короче говоря: (:require .. :refer ..)это новый способ сделать то же самое, что позволяет эффективно отказаться :use, что имеет некоторые недостатки.
переосмыслить
Хорошие примеры. Я люблю примеры, в этом было много смысла.
Астрид
35

Убедитесь, что это действительно облегчает задачу, не требуя, чтобы вы прописывали пространство имен каждый раз, когда вы хотите вызвать функцию, хотя это также может привести к путанице, создавая конфликты пространства имен. Хорошим промежуточным звеном между «use» и «require» является только «использование» функций из пространства имен, которое вы фактически используете.

например:

 (используйте '[clojure-contrib.duck-streams: only (писатель читатель)])
или, что еще лучше, укажите его в начале файла в определении пространства имен:

(ns com.me.project
   (: использовать [clojure.contrib.test-is: only (deftest является run-tests)]))
Артур Ульфельдт
источник
3
Спасибо за включение (каламбур) (ns ...)синтаксиса; Я искал это, но все примеры, которые я нашел, были для простого (use ...).
Павел
1
ОБНОВЛЕНИЕ: этот метод уже устарел в пользу(require '[namepase :refer [var-name1 var-name2]])
Артур Ульфельдт
@ArthurUlfeldt Вы можете обновить свой ответ, чтобы включить (каламбур) это.
Бфонтен
20

Как уже упоминалось, большая разница заключается в том (require 'foo), что с помощью этого вы затем ссылаетесь на имена в пространстве имен библиотеки следующим образом: (foo/bar ...)если вы это сделаете, (use 'foo)то они теперь находятся в вашем текущем пространстве имен (что бы это ни было и при условии отсутствия конфликтов), и вы можете вызвать им нравится (bar ...).

Крис
источник