2010-08-04 11 views
27

Recentemente ho iniziato a studiare Clojure e sto avendo un po 'di difficoltà a sistemare la mia attenzione sui namespace. Come ha detto il creatore di Clojure, i nuovi arrivati ​​spesso lottano per ottenere il concetto giusto. Non capisco chiaramente la differenza tra (use ...) e (require ...). Ad esempio, giocando nel REPL se dico (use 'clojure.contrib.str-utils2) ricevo degli avvisi sulle funzioni nel namespace clojure.core che sono state sostituite da quelle in clojure.contrib.str-utils2, ma ciò non accade quando utilizzo (require 'clojure.contrib.str-utils2). Non sono sicuro di voler sempre sostituire ciò che è in clojure.core, quindi qualcuno può indicare alcune best practice per l'importazione di elementi esterni e la gestione degli spazi dei nomi in Clojure?Differenza nel Clojure tra l'uso e richiedere

Oh e anche, quando devo usare :use e :require? Solo all'interno di (ns ....)?

Grazie in anticipo.

+0

possibile duplicato di [differenza tra uso e richiesta] (http://stackoverflow.com/questions/871997/difference-between-use-and-require) –

risposta

42

La risposta sta nelle docstring:

user> (doc use) 
------------------------- 
clojure.core/use 
([& args]) 
    Like 'require, but also refers to each lib's namespace using 
    clojure.core/refer. Use :use in the ns macro in preference to calling 
    this directly. 

    'use accepts additional options in libspecs: :exclude, :only, :rename. 
    The arguments and semantics for :exclude, :only, and :rename are the same 
    as those documented for clojure.core/refer. 
nil 

E la lunga uno per richiedere:

user> (doc require) 
------------------------- 
clojure.core/require 
([& args]) 
    Loads libs, skipping any that are already loaded. Each argument is 
    either a libspec that identifies a lib, a prefix list that identifies 
    multiple libs whose names share a common prefix, or a flag that modifies 
    how all the identified libs are loaded. Use :require in the ns macro 
    in preference to calling this directly. 

    Libs 

    A 'lib' is a named set of resources in classpath whose contents define a 
    library of Clojure code. Lib names are symbols and each lib is associated 
    with a Clojure namespace and a Java package that share its name. A lib's 
    name also locates its root directory within classpath using Java's 
    package name to classpath-relative path mapping. All resources in a lib 
    should be contained in the directory structure under its root directory. 
    All definitions a lib makes should be in its associated namespace. 

    'require loads a lib by loading its root resource. The root resource path 
    is derived from the lib name in the following manner: 
    Consider a lib named by the symbol 'x.y.z; it has the root directory 
    <classpath>/x/y/, and its root resource is <classpath>/x/y/z.clj. The root 
    resource should contain code to create the lib's namespace (usually by using 
    the ns macro) and load any additional lib resources. 

    Libspecs 

    A libspec is a lib name or a vector containing a lib name followed by 
    options expressed as sequential keywords and arguments. 

    Recognized options: :as 
    :as takes a symbol as its argument and makes that symbol an alias to the 
    lib's namespace in the current namespace. 

    Prefix Lists 

    It's common for Clojure code to depend on several libs whose names have 
    the same prefix. When specifying libs, prefix lists can be used to reduce 
    repetition. A prefix list contains the shared prefix followed by libspecs 
    with the shared prefix removed from the lib names. After removing the 
    prefix, the names that remain must not contain any periods. 

    Flags 

    A flag is a keyword. 
    Recognized flags: :reload, :reload-all, :verbose 
    :reload forces loading of all the identified libs even if they are 
    already loaded 
    :reload-all implies :reload and also forces loading of all libs that the 
    identified libs directly or indirectly load via require or use 
    :verbose triggers printing information about each load, alias, and refer 

    Example: 

    The following would load the libraries clojure.zip and clojure.set 
    abbreviated as 's'. 

    (require '(clojure zip [set :as s])) 
nil 

Entrambi fanno la stessa cosa, ma use va il passo in più e crea mappature per la roba nello spazio dei nomi richiesto nello spazio dei nomi corrente. In questo modo, anziché fare some.namespace/name, ti stai semplicemente riferendo ad esso come name. Mentre questo è conveniente a volte, è meglio usare require o selezionare i singoli oggetti che vuoi piuttosto che inserire l'intero spazio dei nomi. Altrimenti, potresti avere problemi con lo shadowing (dove una var è preferita rispetto ad un'altra con lo stesso nome).

Se non si desidera utilizzare richiedere, ma si sa che cosa si vuole Vars fuori dello spazio dei nomi, si può fare questo:

(ns whatever 
    (:use [some.namespace :only [vars you want]])) 

Se non si sa quale i VAR si sta andando di cui hai bisogno, o se hai bisogno di molto, è meglio usare require. Anche quando richiesto, non è sempre necessario digitare il nome completo. Si può fare questo:

(ns whatever 
    (:require [some.namespace :as sn])) 

e quindi è possibile utilizzare Vars da some.namespace come questo: (sn/somefunction arg1 arg2)

E per rispondere alla tua ultima domanda: cercare di esclusivo uso: richiedere e: utilizzare all'interno di (ns ...). È molto più pulito in questo modo. Non use e require al di fuori di (ns ..) a meno che non si abbia una buona ragione per farlo.