Clojure

Clojure入門 - 名前空間

名前空間と名前

名前空間は、コードとコード内で使用する名前を整理するための手段を提供します。具体的には、関数やその他の値に新しい曖昧でない名前を付けることができます。これらの完全修飾名は、コンテキストを含むため、自然と長くなります。したがって、名前空間は、より短く、入力しやすい名前を使用して、他の関数や値の名前を曖昧に参照するための手段も提供します。

名前空間は、名前のコンテキストとvarのコンテナの両方です。名前空間名は、ピリオドを使用して名前空間の部分を区切るシンボルです(例:`clojure.string`)。慣例により、名前空間名は通常小文字で、単語を区切るために`-`を使用しますが、これは必須ではありません。

Var

Varは、名前(シンボル)と値の関連付けです。名前空間内のVarは、名前空間名とvar名の組み合わせである完全修飾名を持ちます。たとえば、`clojure.string/join`は、`clojure.string`が名前空間を、`join`が名前空間内のvarを参照する完全修飾var名です。すべてのvarは、完全修飾名を使用してグローバルにアクセスできます。慣例により、var名は小文字で、単語を区切るために`-`を使用しますが、これも必須ではありません。var名には、ほとんどの空白以外の文字を含めることができます。

Varは、`def`や`defn`などの`def`で始まる特殊フォームまたはマクロを使用して作成されます。Varは「現在の」名前空間で作成されます。Clojureランタイムは、var `clojure.core/*ns*`に現在の名前空間を追跡します。`in-ns`関数を使用して、現在の名前空間を変更できます。

読み込み

名前空間名は、名前付けコンテキストを提供することに加えて、読み込みのために名前空間のコードを見つける場所に関する慣例も提供します。パスは名前空間名に基づいて作成されます。

  • ピリオドはディレクトリセパレータになります。

  • ハイフンはアンダースコアになります。

  • ファイル拡張子`.clj`が追加されます。

したがって、名前空間名`com.some-example.my-app`は、ロードパス`com/some_example/my_app.clj`になります。ロードパスはJVMクラスパスを使用して検索されます。クラスパスは、一連のディレクトリ位置またはJARファイル(JARは基本的にzipファイルです)です。

リソースが必要な場合、JVMはロードパスの相対位置にあるファイルについて、各クラスパス位置を順番に検索します。したがって、クラスパスが`src:test`の場合、ロードパスは`src/com/some_example/my_app.clj`、次に`test/com/some_example/my_app.clj`で確認されます。

Clojureにはコードを読み込む方法はいくつかありますが、最も一般的には`require`を使用して読み込みが行われます。

この読み込み規則により、ほとんどのClojureは、名前空間構造にマッピングされる階層的な方法で格納された、名前空間とファイルの1対1マッピングで構成されています。

名前空間の宣言

ほとんどのClojureファイルは単一の名前空間を表し、ファイルの先頭で`ns`マクロを使用してその名前空間の依存関係を宣言します。これは多くの場合、次のようになります。

(ns com.some-example.my-app
  "My app example"
  (:require
    [clojure.set :as set]
    [clojure.string :as str]))

`ns`マクロは、名前空間名(上記の規則を使用してファイルパスの位置と一致する必要があります)、オプションのdocstring、そして名前空間に関するいくつかの句を指定します。

refer

デフォルトでは、名前空間を指定せずに現在の名前空間のvarを参照または呼び出すことができます(現在の名前空間は「デフォルト」です)。

さらに、`clojure.core`ライブラリ関数を完全に修飾せずに参照できることに気付いたかもしれません。その理由は、すべての`clojure.core`ライブラリvarが現在の名前空間に`referred`されているためです。`refer`は、他の名前空間のvarを参照する、現在の名前空間のシンボルテーブルのエントリを作成します。

`clojure.core`の参照は`ns`マクロによって行われます。(警告なしにコアの名前を再利用したい場合、これを部分的に抑制する方法があります。)

require

`:require`句は、この名前空間が依存する1つ以上の名前空間を読み込む`require`関数に対応します。各名前空間について、`require`はいくつかのことを行うことができます。

  • 名前空間を読み込む(または再読み込みする)

  • オプションで、読み込まれた名前空間からのvarを参照するために使用できるエイリアスを割り当てる(この名前空間のスコープ内のみ)

  • オプションで、読み込まれた名前空間からのvarを、この名前空間で修飾子なしの名前で使用できるようにする

最後の2つの部分は、名前の使いやすさに関するものです。varは常に完全修飾名で参照できますが、コードで完全修飾名をタイプすることはめったにありません。エイリアスを使用すると、より長い完全修飾エイリアスの短いバージョンを使用できます。referを使用すると、名前空間修飾子なしで名前を使用できます。

`require`では、名前空間は一般的に4つの形式のいずれかを取ります。

  • `clojure.set` - `clojure.set`名前空間を読み込むだけです(まだ読み込まれていない場合)。

  • `[clojure.set :as set]` - `clojure.set`名前空間のエイリアス`set`を作成して読み込みます。

    • これにより、たとえば`set/union`ではなく`clojure.set/union`を使用して`set`内のvarを参照できます。

  • `[clojure.set :refer [union intersection]]` - 特定のvarを読み込んでこの名前空間に参照します。

    • これにより、`clojure.set/union`ではなく`union`を使用できます。

  • `[company.application.component.user :as-alias user]` - 名前空間を読み込むことなく、`company.application.component.user`の名前空間のエイリアス`user`を作成します。

    • 通常、`:as-alias`を使用する場合、名前空間は修飾子として使用されますが、読み込み可能な名前空間ではありません。

    • これにより、名前空間修飾子の省略形を使用できます。例:マップの作成:`{::user/id 1}`、スペックの登録:`(s/def ::user/id int?)`、デストラクチャリング:`(defn find-by-id [{::user/keys [id]}] ,,,)`

Javaクラスとインポート

Varに加えて、ClojureはJava相互運用性とパッケージに存在するJavaクラスへのアクセスもサポートしています。Javaクラスは常に、完全修飾クラス名(例:`java.util.Date`)を使用して参照できます。

`ns`マクロは、`java.lang`パッケージのクラスもインポートするため、完全修飾クラス名ではなく、クラス名のみを使用できます。たとえば、`java.lang.String`ではなく`String`などです。

`:refer`と同様に、`ns`マクロには`:import`句(`import`マクロでサポートされています)があり、修飾子なしの名前で使用する他のクラスをインポートできます。

(ns com.some-example.my-app2
  (:import
    [java.util Date UUID]
	[java.io File]))

この例では、`java.util`パッケージから`Date`クラスと`UUID`クラス、`java.io`パッケージから`File`クラスをインポートします。