今回は…
モジュールについてお話します。
モジュールを利用する利点は、ファイルを分割することにあります。
似たような種類の関数や、変数などの定義をまとめておくための仕組みです。
下のサンプルコードでは、関数をモジュールにまとめて定義しています。
D言語ではモジュールはファイルと1:1対応となっています。つまり、モジュール名=ファイル名です。
ただし、モジュール名には.dという拡張子は必要ありません。
いままでは特に指定しなくてもファイル名が直接モジュール名として判定されてきました。
しかし、main関数のあるファイル以外には、モジュールを明示的に指定してやるとよいでしょう。
詳しくは述べませんが、そうしないと、たとえばdmdのコンパイラスイッチ-Iを指定した場合などに不都合な場合があるためです。
今回のミソ
- ファイルの一番最初に以下のようにすることで明示的にモジュール名を指定する。ここでのXXXXはファイル名から.dを取り除いたもの。
module XXXX;
- モジュール内で定義されたファイルスコープの変数や関数は他のモジュールからは使うことができない。
- 逆に、グローバルスコープの変数や関数は他のモジュールで使うことができる。
サンプルコード
sample1401.d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | - ! - | ! - | ! - | ! - | ! - | ! - | ! |
|
まとめ
今回のだけではあまりありがたみがありませんね。
このモジュールという概念は、importと組み合わせることで、ファイルを分割することに役立ちます。
そんなimportの使い方は次回。
それでは次へどうぞ~
今回は…
前回のmoduleで定義されたモジュールをimportします。
いままで
|
等としていたのもすべてモジュールを読み込むために行っていたものなのです。
importでモジュールを読み込むと、読み込んだモジュール内で、グローバルスコープとして定義されたものを、importしたモジュールの中で利用することができるようになります。
サンプルコード
sample1402p.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| - - | | | ! | - | | | ! | - | | ! | ! |
|
Tango用はこちら |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| - - | | | ! | - | | | ! | - | | ! | ! |
|
まとめ
今回はimportで自分の作ったモジュールを読み込むことを行いました。
注意しなければならないのは、コンパイルの際、実行結果に示すように、dmdでは、importするモジュールも、importされるモジュールも両方とも同時にコンパイルしなければならないことです。
この講座の実行結果の例の部分では、毎回 -run を用いることで、実行ファイルを作成して即時実行するようにしていますが、
この場合は -run より前にmain関数のないファイルを、-run の直後にmain関数のあるファイルを指定します。
実行ファイルを生成したい場合は順番に関係なく、同時にまとめてコンパイルすればよいのです。
1 |
|
dsssやbud等を使ってコンパイルする際には同時に指定する必要がないこともあります。
今回は…
モジュールをカテゴリごとに分類して、フォルダわけのような階層的な構造とするための、パッケージという仕組みを紹介します。
パッケージはファイルシステムでいうフォルダのような存在です。
今まで使用してきたものにその様子をうかがうことができます。
- std.stdio
- std.conv
- std.string
など、これまでに扱ってきたもともとあるモジュールには、stdというものが名前の先頭についているかと思います。
これこそが、パッケージというものなのです。
たとえば、std.stdioは、stdパッケージに含まれる、stdioモジュールなのだということがわかります。
Tangoでは、 tango.io.Stdout など、より深い階層化が行われています。
tangoパッケージの中のioパッケージの中のStdoutモジュールということになりますね。
実際にパッケージを構成するときも、フォルダ構造を同じくします。
たとえば、
- main.dファイル
- testフォルダ
- utilフォルダ
- test.dファイル
- func.dファイル
- utilフォルダ
というようなフォルダ構成があったとしましょう。
ファイルは
- main.d
- test/util/test.d
- test/func.d
の3つになりますね。
これらのそれぞれに対応したパッケージとモジュール名は、このようになります。
- main
- test.util.test
- test.func
階層ごとに、.(ピリオド)で区切り、最後はファイル名から.dを抜いたものということになります。
ひとつ注意しなければならないことは、パッケージ名と同じモジュールは作成できないことです。
つまり、
- main.d
- test.d
- test/func.d
というようなことはできません。
testモジュールと、testパッケージがかぶってしまうためです。
ほかにもパッケージ名やモジュール名はいくつかの制約を受けます。
今回のミソ
- パッケージにより、モジュールを階層化することができる。
- パッケージ名はフォルダ名と同じです
- パッケージ名やモジュール名には、.(ピリオド)が使えない
- パッケージ名やモジュール名には、予約語が使えない
- パッケージ名やモジュール名には、基本的にすべて小文字*2
サンプルコード
main.d
1
2
3
4
5
6
7
8
9
| - | | ! |
|
sample/func.d
sample/util/test.d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | - | ! - - ! | - | ! - | ! ! - - ! | - | ! - | ! ! - | | |
|
まとめ
もちろん今回も全てのファイルを同時にコンパイルします。
このように、階層化する理由として、カテゴライズがあります。
Tangoでは、
- tango.io.*
のパッケージに属するものは、I/O*4関連のモジュールであることが、パッケージ名から一目瞭然です。
上手にパッケージやモジュールの名前を決めていきましょう。*5
今回は…
名前空間についてお話します。
名前空間というのは、名前の衝突を避けるための仕組みです。
詳しくは[[Wikipedia:名前空間]]にうまく表記されているようなのでそちらを参考にしてもらうとして…
実際にどんな場面で役に立つのか?を中心にお話しします。
特に名前空間が役に立つ場面は、グローバルスコープに、同じ名前があったときのアクセスです。
たとえば、モジュールhogeにget関数があったとします。
1 2 3 4 5 |
|
また、モジュールfugaにもget関数があったとします。
1 2 3 4 5 |
|
このとき、これらhogeとhugaを同時にインポートした場合、どうしたらいいでしょうか?
get() として呼び出したらどうなるでしょうか?
1 2 3 4 5 6 7 8 9 |
|
コンパイルすると、次のようなエラーメッセージが出てコンパイルできません。
1 2 |
|
「モジュールhogeのget関数と、モジュールfugaのget関数がかぶってるよ!どっち呼んだらいいかわかんないよ!」といわれているわけです。
ここで登場するのが、「名前空間」というわけですね。
D言語では、モジュールが自動でその中身をスコープとする名前空間を形成します。
つまり、モジュール名を指定すれば、名前空間にアクセスできるってことになりますね。
前述の例では、 hoge.get() や fuga.get() のようにすることで名前空間を使ったアクセスを行うことができるわけです。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
今回のミソ
- グローバルスコープに同じ名前の関数や変数、型が存在する場合、直接使おうとするとコンパイルエラーが発生する
- 名前の衝突を避けるためには名前空間を使う。
- D言語ではモジュールが名前空間を作る
- 名前空間の使い方は、以下のように.(ピリオド)を使う
モジュール名.使いたい名前
サンプルコード
main.d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | - ! - ! - ! - - ! - ! | ! - | ! - - ! | - | ! ! - - ! | - | ! ! |
|
hoge.d
fuga.d
まとめ
グローバルスコープで名前が衝突してしまうのは、できれば避けたい事態ですね。
これを避けるために、ファイルスコープ*6があるわけです。
外部にさらす必要のない関数や変数、型*7はどんどんprivateにしたほうがいいでしょう。
また、モジュールがパッケージに属している場合は、パッケージ名から書いてくださいね。
例として、Tangoの整数を文字列に変換するtoString関数と、実数を文字列に変換するtoString関数がうまい具合にかぶっているので、これでパッケージからのアクセスの使い方を紹介します。
|
今回は…
前回にパッケージ名からすべてモジュール名を明記して呼び出すことで名前空間が使えることを示しましたが、これ、長くないでしょうか。
いちいち毎回記述するの、めんどうですよね。
そんなときに使えるのが、これ。
改名インポート。モジュール名を別の名前に変えて名前空間にアクセスすることができます。
|
他にもインポートに関するものはいくつかあります。
staticインポート。必ずモジュール名を明記しなければ名前にアクセスできません。
|
選択インポート。使いたいものだけ選択してインポートすることができます。
|
改名選択インポート。改名と選択を組み合わせた感じ
|
publicインポート。これを行ったモジュールをimportするだけで、publicの付いたモジュールが使えるようになる。まとめてインポートさせたいときなどに有効かも知れない。
|
詳しくは公式ページのほうに載っているので、参考にしていただきたい。
今回のミソ
- staticインポート…必ず名前空間をつけなければアクセスできなくする
- 改名インポート…名前空間の名前を変えてインポートする
- 選択インポート…関数などの名前を変えてインポートする
- 改名選択インポート…上二つの組み合わせ。
- publicインポート…行ったモジュール自身をインポートすると同時にインポートされる
第14章のミソ
- モジュールを読み込むにはimportを使って次のようにします。
import modulename;
- importされた関数はそのファイルで使うことができる。
- パッケージにより、モジュールを階層化することができる。
- パッケージ名はフォルダ名と同じです
- パッケージ名やモジュール名には、.(ピリオド)が使えない
- パッケージ名やモジュール名には、予約語が使えない
- パッケージ名やモジュール名には、基本的にすべて小文字*2
- グローバルスコープに同じ名前の関数や変数、型が存在する場合、直接使おうとするとコンパイルエラーが発生する
- 名前の衝突を避けるためには名前空間を使う。
- D言語ではモジュールが名前空間を作る
- 名前空間の使い方は、以下のように.(ピリオド)を使う
モジュール名.使いたい名前
- staticインポート…必ず名前空間をつけなければアクセスできなくする
- 改名インポート…名前空間の名前を変えてインポートする
- 選択インポート…関数などの名前を変えてインポートする
- 改名選択インポート…上二つの組み合わせ。
- publicインポート…行ったモジュール自身をインポートすると同時にインポートされる
宿題
モジュールを分割してみましょう。
- モジュール util.func に、二つの整数を足し算する int add(int a, int b) 関数を記述
- モジュール util.textfunc に、二つの文字列を連結する char[] add(char[] a, char[] b) 関数を記述
- 以下のコードの _____ を埋めて、コンパイルが通るようにしましょう
import util._____; import _____ util.textfunc: _____; import stdio = _____: _____ = writefln; int main(char[][] args) { _____.output( util._____._____(10, 45) ); _____.output( txtfn.add("hogehoge", "fugafuga") ); }
1 2
55 hogehogefugafuga
コメント
今回の宿題の空欄が多いでしょうか?
ヒントは…
- モジュール名
- 改名インポート
- 選択インポート
- 改名選択インポート
- 改名選択インポート
- 改名選択インポートされた関数にアクセス
- モジュール名
- 関数名
- 改名選択インポートされた関数にアクセス
となっております。それではお次にまいりましょう。
次回はいよいよ、オブジェクト指向です。
それではお次へどうぞ~
投票とコメント
Show recent 10 comments. Go to the comment page.
*1 今回はTangoとPhobosの差はありません
*2 これは仕様ではなく、推奨されているものです。
*3 特に今回の物は、内部で分岐させることでPhobosの時とTangoの時両方でコンパイルできるようにしてあります。
*4 入出力
*5 ただし、Tangoの場合は本家で推奨しているような、すべて小文字のモジュール名は採用していないようです…
*6 privateな宣言や定義のこと
*7 構造体やクラスなど
Page Info | |
---|---|
Page Name : | Articles/D言語入門講座/第14章 - モジュール |
Page aliases : | None |
Page owner : | SHOO |
Can Read | |
Groups : | All visitors |
Users : | All visitors |
Can Edit | |
Groups : | No one |
Users : | SHOO |