różnica między użyciem a wymaganiem

155

Czy ktoś może wyjaśnić różnicę między usei require, zarówno w przypadku użycia bezpośrednio, jak :usei :requirew nsmakrze?

Jegschemesch
źródło
2
Zobacz także stackoverflow.com/questions/10358149/… w odniesieniu do makra ns; w clojure 1.4 sugeruje się użycie: wymagaj preferencji: użyj
Korny

Odpowiedzi:

101

requireładuje biblioteki (które nie są jeszcze załadowane), userobi to samo, a dodatkowo odwołuje się do ich przestrzeni nazw clojure.core/refer(więc masz również możliwość używania :excludeitp. tak jak z clojure.core/refer). Oba są zalecane nsraczej do użycia w niż bezpośrednio.

Alex Martelli
źródło
3
Gdybym potrzebował lib foo, to aby użyć bar w foo, musiałbym za każdym razem pisać foo / bar, prawda? Dlaczego miałbyś chcieć załadować bibliotekę w ns, ale potem nie odsyłać jej do ns? Myślę, że możesz martwić się kolizjami i nie chcesz się martwić o ich godzenie, prawda?
Jegschemesch
12
brak konieczności uzgadniania kolizji to dobry punkt, a bardziej ogólnie istnieje styl programowania, który mówi, że „przestrzenie nazw to świetny pomysł, powinniśmy ich mieć więcej” (z „Zen of Python”) - więc np. ten styl zaleca nie używa "using namespace foo;" w C ++, aby czytelnicy i opiekunowie kodu nie musieli martwić się „skąd pochodzi ten pasek”, ale zamiast tego zobaczą bardziej wyraźne foo :: bar. require (vs use) obsługuje ten styl „jawnych przestrzeni nazw”.
Alex Martelli
2
Alex daje dobrą, ale przestarzałą odpowiedź. Jak @overthink wskazuje poniżej, po udzieleniu tej odpowiedzi idiomatyczne zalecenia clojure wymagają nadmiernego użycia. patrz: dev.clojure.org/jira/browse/CLJ-879
Phil Cooper
Chociaż jest to przyjęta i najbardziej pozytywna odpowiedź, jest stara i przedstawia przestarzały pogląd. Lepszą odpowiedzią jest @rzv: stackoverflow.com/a/16429572/172272
Didier A.
65

Dołączanie funkcji zewnętrznych za pomocą requirei jest idiomatyczne refer. Unikasz konfliktów przestrzeni nazw, dołączasz tylko funkcje, których faktycznie używasz / potrzebujesz, i jawnie deklarujesz lokalizację każdej funkcji:

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

Nie muszę wywoływać tej funkcji, poprzedzając ją jej przestrzenią nazw:

(wrap-reload) ; works

Jeśli nie używasz refer, musisz poprzedzić go przestrzenią nazw:

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

Jeśli wybierzesz usezamiast tego, (prawie) zawsze używaj only:

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

W przeciwnym razie dołączasz wszystko, co sprawia, że ​​jest to zarówno niepotrzebnie duża operacja, jak i bardzo mylące dla innych programistów, aby dowiedzieć się, gdzie znajdują się funkcje.

Bardzo polecam również ten blog jako źródło informacji o przestrzeniach nazw Clojure.

rzv
źródło
Czy wiesz, czy na końcu jest jakaś różnica między (:use foo :only [bar])i (:require foo :refer [bar])? Wydaje się dziwne, że można to zrobić na dwa sposoby.
przemyślenie
10
Wygląda na to, że stackoverflow.com/a/10370672/69689 odpowiada na moje pytanie. W skrócie: (:require .. :refer ..)to nowy sposób na zrobienie tego samego, który pozwala skutecznie wycofać z użycia :use, co ma pewne wady.
przemyślenie
Dobre przykłady. Uwielbiam przykłady, to miało sens.
Astrid
35

Używanie sure sprawia, że ​​jest to łatwiejsze, ponieważ nie wymaga przeliterowania przestrzeni nazw za każdym razem, gdy chcesz wywołać funkcję, chociaż może również narobić bałaganu, tworząc konflikty przestrzeni nazw. Dobrym punktem pośrednim między „użyj” a „wymagaj” jest „używanie” tylko funkcji z przestrzeni nazw, której faktycznie używasz.

na przykład:

 (użyj '[clojure-contrib.duck-streams: only (pisarz czytelnik)])
lub nawet lepiej, określ go na górze pliku w definicji przestrzeni nazw:

(ns com.me.project
   (: use [clojure.contrib.test-is: only (deftest to run-tests)]))
Arthur Ulfeldt
źródło
3
Dzięki za dołączenie (kalambur) (ns ...)składni; Szukałem tego, ale wszystkie przykłady, które znalazłem, były proste (use ...).
paul
1
AKTUALIZACJA: ta metoda została teraz przestarzała na korzyść(require '[namepase :refer [var-name1 var-name2]])
Arthur Ulfeldt
@ArthurUlfeldt Możesz zaktualizować swoją odpowiedź, dodając (kalambur) to.
bfontaine
20

Jak już wspomniano, duża różnica polega na tym (require 'foo), że z , następnie odwołujesz się do nazw w przestrzeni nazw biblioteki w ten sposób: (foo/bar ...)jeśli to zrobisz (use 'foo), znajdują się one teraz w twojej bieżącej przestrzeni nazw (cokolwiek to może być i pod warunkiem, że nie ma konfliktów) i możesz wywołać im się podoba (bar ...).

Chris
źródło