文書の過去の版を表示しています。
モジュール
このチュートリアルでは数行程度の僅かなコードのプログラムしか作ってきませんでした。現実的なプログラムではもっと多くのコードが必要になります。多くの場合は一つのファイルに全てのコードを詰め込むよりも、そのコードの特性によって複数のファイルに分割したほうが管理しやすくなります。それぞれのファイルは独立したコンパイル単位、つまり、別々にコンパイルされます。そして、通常は、一つのファイルが一つのモジュールになります。
インポート
モジュールはインポートして使用します。
例えば、myAppというプログラムがあったとして、次のような構成になっていたとします。
myApp/ ├── main.nim ├── moduleA.nim ├── moduleB.nim └── other/ ├── moduleA.nim └── moduleB.nim
そして、main.nimはmoduleAとmoduleBを使用し、moduleAはotherのmoduleAを、moduleBはotherのmoduleBを使用していたとします。このような依存関係があるとき、各ファイルでimport文を使用して、それぞれ必要とするモジュールをインポートします。
<codeprism lang=nim> # main.nim import moduleA import moduleB …
# moduleA.nim import other/moduleA …
# moduleB.nim import other/moduleA
# other/moduleA.nim …
# other/moduleB.nim … </codeprism>
このプログラムをビルドするには、トップレベルのソースファイルであるmain.nimだけをコンパイルに渡します。依存するモジュールの解決とソースファイルのコンパイルは自動的に行われます。
$ cd /path/to/myApp $ nim compile --out:myApp main.nim Hint: used config file '/home/freemikan/.choosenim/toolchains/nim-2.0.2/config/nim.cfg' [Conf] Hint: used config file '/home/freemikan/.choosenim/toolchains/nim-2.0.2/config/config.nims' [Conf] ........................................................................ Hint: [Link] Hint: mm: orc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code) 27620 lines; 0.120s; 30.332MiB peakmem; proj: /home/freemikan/code/NimTutorial/myApp/main.nim; out: /home/freemikan/code/NimTutorial/myApp/myApp [SuccessX]
メッセージに含まれる“out: /home/freemikan/code/NimTutorial/myApp/myApp [SuccessX]”の部分から、正常にmain.rsがコンパイルされて、myAppが生成されたことが確認できます。1)
エクスポート
モジュール内で定義されたシンボル、つまり、変数やプロシージャはデフォルトではモジュール外からアクセスできません。アクセスできるようにするには、エクスポートすることを明示しなければなりません。エクスポートするには、名前に*
をつけます。
<codeprism lang=nim> # moduleA.nim let foo* = 100 let bar = 200
# main.nim import moduleA echo foo # OK ⇒ 100 echo bar # コンパイルエラー! </codeprism>
上の例では、foo*
は*
が付与さているのでエクスポートされます。bar
はそうではないのでエクスポートされません。moduleAをインポートするmain.nimでは、foo
にのみアクセス可能で、bar
はアクセス不可です。main.nimをコンパイルするとエラーになります。
Error: undeclared identifier: 'bar'
main.nimではbar
が全く見えていないことが分かります。
インポートされるシンボルは直接インポートするモジュール内でエクスポートされているものだけです。
<codeprism lang=nim> # other/moduleA.nim let bar* = 200
# moduleA.nim import other/moduleA let foo* = 100
# main.nim import moduleA echo foo # OK ⇒ 100 echo bar # コンパイルエラー! </codeprism>
main.nimからはother/moduleAでエクスポートされているbar
を認識することが出来ません。もし、moudleAがインポートしたother/moduleAもmain.nimで使えるようにしたいなら、その判断はmoduleAに委ねられます。moduleAがother/moduleAを再エクスポートすれば可能となります。
<codeprism lang=nim> # other/moduleA.nim let bar* = 200
# moduleA.nim import other/moduleA export moduleA # other/moduleAを再エクスポート let foo* = 100
# main.nim import moduleA echo foo # OK ⇒ 100 echo bar # OK ⇒ 200 </codeprism>
定数やプロシージャについても同じ規則に従います。
<codeprism lang=nim> # other/moduleA.nim const BAZ* = 300 proc add3*(a, b, c: int): int = a + b + c
# moduleA.nim import other/moduleA const FOO* = 100 const BAR = 200 proc add2*(a, b: int): int = a + b proc sub2(a, b: int): int = a - b
# main.nim import moduleA echo FOO # OK ⇒ 100 # echo BAR # コンパイルエラー! # echo BAZ # コンパイルエラー! echo add2(1, 2) # OK ⇒ 3 # echo sub2(1, 2) # コンパイルエラー! # echo add3(1, 2, 3) # コンパイルエラー! </codeprism>
まとめると次のとおりです。
- エクスポートするシンボルには
*
を付ける。そうでなければエクスポートされない。 - 最エクスポートされていないかぎり、直接インポートするモジュール内でエクスポートされたシンボルしか有効にならない。
- インポートするモジュールのパスはディレクトリ構造が反映される。
このようにかなりシンプルな規則となっています。
標準ライブラリ
標準ライブラリもモジュールの仕組みを使って提供されていますので、使用したいものがあればまずインポートする必要があります。ただし、systemモジュールは例外で、自動的にインポートされます。このモジュールにはint
やbool
などの基本的な型、array
やseq
とそのプロシージャなど必要不可欠なものが含まれています。