user=> (def x)
#'user/x
user=> x
#object[clojure.lang.Var$Unbound 0x14008db3 "Unbound: #'user/x"]
Clojureは、変化する値への永続的な参照を維持する必要がある場合を認識した実用的な言語であり、制御された方法でそれを行うための4つの異なるメカニズム(Var、Ref、エージェント、アトム)を提供します。 Varは、スレッドごとに動的に再バインド(新しいストレージロケーションに)できる可変ストレージロケーションを参照するためのメカニズムを提供します。すべてのVarは、ルートバインディングを持つことができます(必須ではありません)。ルートバインディングは、スレッドごとのバインディングを持たないすべての スレッドで共有されるバインディングです。したがって、Varの値は、そのスレッドごとのバインディングの値、または、値を要求しているスレッドにバインドされていない場合は、ルートバインディングの値(存在する場合)です。
特殊形式def
は、Varを作成(およびインターン)します。 Varがまだ存在せず、初期値が指定されていない場合、varは未バインドです。
user=> (def x)
#'user/x
user=> x
#object[clojure.lang.Var$Unbound 0x14008db3 "Unbound: #'user/x"]
初期値を指定すると、ルートがバインドされます(既にバインドされている場合でも)。
user=> (def x 1)
#'user/x
user=> x
1
デフォルトではVarは静的ですが、マクロbindingを介してスレッドごとのバインディングを許可するために、Varを動的としてマークできます。 各スレッド内では、スタック規律に従います。
user=> (def ^:dynamic x 1)
user=> (def ^:dynamic y 1)
user=> (+ x y)
2
user=> (binding [x 2 y 3]
(+ x y))
5
user=> (+ x y)
2
binding
で作成されたバインディングは、他のスレッドからは見えません。 同様に、binding
で作成されたバインディングは割り当てることができ、ネストされたコンテキストがコールスタックに配置される前にコードと通信する手段を提供します。 この機能は、上記のコードブロックのように、メタデータタグ^:dynamic
をtrueに設定することによってのみオプトインできます。 コンテキスト内で静的Varを再定義したい場合があります。Clojure(バージョン1.3以降)は、そのような目的のために関数with-redefsとwith-redefs-fnを提供しています。
defnで定義された関数はVarに格納されるため、実行中のプログラムで関数を再定義できます。 これにより、アスペクト指向プログラミングまたはコンテキスト指向プログラミングの可能性の多くも実現します。 たとえば、特定のコールコンテキストまたはスレッドでのみ、ロギング動作で関数をラップできます。
代入の特殊形式。
最初のオペランドがシンボルの場合、グローバルvarに解決される必要があります。 varの現在のスレッドバインディングの値は、exprの値に設定されます。 現在、set!を使用してvarのルートバインディングを設定しようとするとエラーが発生します。つまり、varの割り当てはスレッドローカルです。 いずれの場合も、exprの値が返されます。
注-関数のパラメーターまたはローカルバインディングに割り当てることはできません。 Clojureでは、Javaフィールド、Var、Ref、およびエージェントのみが変更可能です。
with-local-varsを使用することにより、インターンされていないvarを作成できます。 これらのvarは、自由シンボルの解決中には見つからず、それらの値には手動でアクセスする必要があります。 しかし、それらは便利なスレッドローカルの可変セルとして機能することができます。
varを作成するフォームdef
、defn
、defmacro
などは、標準のvar メタデータセットを使用してvarを記述します。 これらのフォームの一部は、明示的な構文を使用してメタデータに格納されている値を受け入れますが、一般に、そのメタデータをvarシンボル上のマップとして指定することもできます。
一般的なvarメタデータキー(すべてvar定義ではオプション)
:doc
- varを文書化する文字列。通常、docstringパラメータによって設定されます
:added
- このvarが追加されたバージョンを文書化する文字列
:private
- 多くの場合、defn-
によって設定されるブール値フラグ。作成者によって、このvarが実装の詳細であるという意図を表明するために使用されます。 プライベートvarはグローバルにアクセスできますが、プライベートではないvarにフィルタリングするns-
…関数では参照またはリストされません。
:arglists
- arglistsのコレクション。指定されていない場合は自動的に生成されます。ほとんどの場合、マクロ構文を文書化するために使用されます
:macro
- defmacro
によって自動的に追加されるブール値フラグ(通常は直接使用されません)
:tag
- varの値の型、またはvarに保持されている関数の戻り値の型の型識別子(通常はクラス)。 varメタデータは評価されるため、varの^long
などの型ヒントは、long
プリミティブ型ヒントではなく、long
関数に評価されます。 一般に、defn varのarglistに型ヒントを使用することをお勧めします。
:test
- clojure.test
フレームワークは、このキーを使用してユニットテストをvarに添付します(通常は直接使用されません)
:dynamic
- varがスレッドコンテキストで動的に再バインドされる可能性があることを示します(上記を参照)。 動的varは、直接リンクでコンパイルする場合、直接リンクされません。
:redef
- 直接リンクでコンパイルする場合、varを直接リンクしないことを示します(再定義できるようにするため)
:static
- 使用されなくなりました(元々varはデフォルトで動的でしたが、現在はデフォルトで静的です)
:const
- varがコンパイル時定数であり、コンパイラが値をそれを使用するコードにインラインできることを示します。 注:これはめったに必要ではなく、コンパイル時(読み取りは行いますが、評価は行いません)の定数(数値、文字列など(クラス、関数、参照型などではありません))でのみ機能します。 const varを再定義または動的にバインドしても、既にコンパイルされてランタイムにロードされているvarを使用するコードには影響しません。
コンパイル中の直接リンクとメタデータの省略の詳細については、コンパイラオプションも参照してください。
def
のバリアント:defn defn- definline defmacro defmethod defmulti defonce defstruct
インターンされたVarの操作:declare intern binding find-var var
Varオブジェクトの操作:with-local-vars var-get var-set alter-var-root var? with-redefs with-redefs-fn
Varバリデーター:set-validator! get-validator
Varメタデータの使用:doc find-doc test