ExcelVBA入門第11回 スコープ(適用範囲)
第9回、第10回で、モジュールとプロシージャの解説をしてきました。これを扱うのに重要なのが、「スコープ(適用範囲)」です。変数を使うのにも大事な知識ですので、おさえておきましょう!
変数やプロシージャには、「範囲」を設ける
スコープは、「適用範囲」という意味です。このスコープにより、変数やプロシージャが「どこからでも使える」「ここしか使えない」などという制限をします。
1つのモジュール内、1つのプロシージャだけで完結するモノを作るならば、スコープを意識しなくても動くものは作れます。でも、効率化やメンテナンス性を考えて、プロシージャを分割したり、複数のモジュールを使ったりするならば、ちゃんと覚えておきたい知識です。
変数の場合
プロシージャ内だけ使える、Dim
Dimで宣言した変数は、そのプロシージャの中でだけ有効です。1つの村でこまめに働く小人さんです。
小人さん(変数)たちは、基本的にはDimで、自分の村(プロシージャ)のことはできるだけ自分たちだけでなんとかします。村の中に居れば、外よりも事故や病気などの可能性が低いからです。
Sub Sample() Dim i As Integer, j As Integer For i = 1 To 10 For j = 1 To 10 Cells(i, j) = i * j Next j Next i End Sub
Dim変数は自分の村から出ないので、他の村でも同じ名前の小人さんが居たりします。特に、上記のようなループで使うi
やj
などの変数は、あちこちの村に居ますが、同じ名前でも別の小人さんです。
モジュールの中で使える、Private
Privateで宣言した変数は、プロシージャを超えて、1つのモジュールの中で働くことができます。村の垣根を超えて、島の中を自由に動ける小人さんです。
村の中では手に入らなかったり、外に持ち出したりしたい物資が出てきたら、Private という役職の小人さんにお願いして、村を行き来してもらいます。
モジュールでは、一番上のプロシージャの更に上の先頭部分を「宣言セクション」と呼び、Private はそこで宣言して使います。
Private userName As String '宣言セクションで Private 変数を宣言 Sub Main() 'メインのプロシージャ Call SetName Call ShowName End Sub Sub SetName() userName = "あああ" End Sub Sub ShowName() MsgBox userName End Sub
たとえば、こんなコードのMain
プロシージャを走らせた場合、userName
という変数がプロシージャを超えて使われ、「あああ」というメッセージボックスが表示されます。
このuserName
は Private なので、他のモジュールからは使うことはできません。「できません」という言い方をすると、なんだか「不便」な印象を受けてしまいますが、逆の言い方をすれば、外からの干渉を受けないので「安全性が高い」のです。
特に Private は、モジュール内ならばいろんなプロシージャから自由に使えて、外のモジュールからは安全、という絶妙なバランスを作れるので、結構有能な小人さんなんです。
なお、宣言セクションでDim宣言をした変数は、Private変数と同じ範囲で使うことができます。ですが、まぎらわしいのでDimはプロシージャ内で使うだけにしておいたほうがいいんじゃないかなー、と個人的に思っています。
どこでも使える、Public
Publicで宣言した変数は、モジュールさえも超えて、どこでも働くことができます。船に乗って他のどの島のどの村でも行き来できる、コミュ力MAXな小人さんです。
使い方は Private と一緒で、宣言セクションで使います。
'## 標準モジュール ## Public userName As String '宣言セクションで Public 変数を宣言 Sub Main() UserForm1.Show MsgBox userName End Sub
'## フォームモジュール ## Private Sub CommandButton1_Click() userName = Me.TextBox1 End Sub
こんなコードのMain
プロシージャを走らせた場合、UserForm1 の TextBox1 の値を Public な変数であるuserName
に入れて、標準モジュールで使うことができます。このようなに、いろんなモジュールをまたいで使いたい変数などには、絶大な力を発揮してくれます。
ただし、Public や Private な小人さんはとても便利ですが、注意しなくてはならないことがあります。
行ける範囲が大きいということは、逆に言えば干渉される範囲も大きいということです。大事な物資を運んでいる途中で、盗まれたり、違うものにすり替えられたりする可能性が高くなるのです。悪意がなくても、ちょっと立ち寄った村でうっかり荷物を取り違えたりする可能性だってあります。
便利なぶん、バグになることも多くなりがちなので、スコープの大きな変数は最小限にしたり、「他の方法でもできないか」ということも検討してみましょう。たとえば、プロシージャやモジュールを超える場合は、引数という形で変数を受け渡すこともできます(第10回参照)。
使う場合は、いろんな場所で使うことを想定して、「わかりやすい名前」で「重複しない」変数名にするなどの配慮が必要です。
プロシージャの場合
ここまで、変数についてのスコープを解説してきましたが、プロシージャにも Private と Public があります。
モジュール内からでないと呼び出せない、Private
第9回で、シート・ブック・フォームモジュールに自動挿入されたプロシージャを見てみましょう。
↑シートモジュール
↑ブックモジュール
↑フォームモジュール
プロシージャの頭に、Private が付いていますね! これらのプロシージャは、すべてシート・ブック・フォームのオブジェクトに対して「何か操作されたとき」をきっかけに起動するプロシージャなので、別のモジュールからは自由に動かせないようになっているんです。操作してないのに外から勝手に動かされたら気持ち悪いですもんね。
自作のプロシージャでも、頭に Private と付けると、そのモジュールからしか呼び出せなくなります。もちろん、Sub でも Function でも同じです。
どこからでも呼び出せる、Public
さて、ここまでの流れで、「ははーん、じゃあプロシージャの頭に Public を付ければいいんだな? それでどこからでも呼び出せるプロシージャになるんだな?」って思いますよね。そのとおり、正解です!!
正解なんですが、実は、プロシージャの Public は、省略できるという特徴があるんです。つまり、プロシージャの頭に何もついていない場合は Public と判断される、ということです。
ということは、今まで基本だ基本だと言ってさんざん書いてきた
Sub Sample() '略 End Sub
この形は、すでに Public なプロシージャだったのです。
Public Sub Sample() '略 End Sub
これと同じ意味になります。Functionなどの他のプロシージャも、一緒です。
初心者向けとして書いてきたので、最初の一歩の Sub プロシージャから、いきなり Public のお話は難しいと思ってここまで言及せずにきましたが、実は最初から Public を使っていたんですね。
Public プロシージャは、「モジュール名.プロシージャ名」と指定して書くことで、外のモジュールからでも呼び出すことができます。
ちなみに、さきほどの例で挙げたシート・ブック・フォームの Priavate なプロシージャを Public にすることも可能です。
なお、標準モジュールに書いた Public プロシージャを別のモジュールから呼び出すときは、モジュール名は省略できます。機能のデフォルトとされる部分は、記述が省略可能なことが多いです。
ただし、Public や 標準モジュール名 などの「省略可能な部分」を、「あえて記述する」という方針でコードを書く場合もあります。そうすることで、「暗黙のルール」のような曖昧さが回避でき、チームを組んでプログラミングするときなどは、そういった細かいルールを設けておくと、後でメンテナンスがしやすくなるのです。第10回の「命名規則」も、そのひとつです。
今後は、「どんなことをしたいか」という目的をよく考えて、プロシージャも Public や Private の使い分けができるようになると、コードのメンテナンス性が変わってきます。
スコープは、基本的に「小さめ」で!
変数もプロシージャも、単純に考えると、全部「どこからでも使える」ほうが便利な気がしちゃいますが、安全面から Public はあまり多用しないほうが良いとされています。
できるだけ小さな範囲のスコープでプログラミングをすることということは、「誤作動を防ぐ」「安全性を高める」という意味になりますので、慣れてきたらぜひ意識してみてください。
ほかの入門記事はこちら
- ExcelVBA入門第0回 始める前に
- ExcelVBA入門第1回 動かしてみる
- ExcelVBA入門第2回 とりあえず覚えておくべきこと
- ExcelVBA入門第3回 変数の宣言
- ExcelVBA入門第4回 RangeとCells
- ExcelVBA入門第5回 ステップ実行
- ExcelVBA入門第6回 If ~ End Ifステートメント
- ExcelVBA入門第7回 インデントとコメントアウト
- ExcelVBA入門第8回 繰り返し処理
- ExcelVBA入門第9回 5種類のモジュールの違い
- ExcelVBA入門第10回 3種類のプロシージャと命名規則
- ExcelVBA入門第11回 スコープ(適用範囲)
- これからExcelのマクロを始めたいという方に!簡単な練習問題作りました。
- 私がExcelVBAでよく使う便利なコード・スニペットまとめ
- プログラム初心者さんへ贈る、エラーが起きたら試してみて欲しいこと
- ExcelVBAのクラスモジュールって何?という人向けの使い方まとめ
書籍を執筆しています。
コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)
YouTubeでQ&Aコンテンツを企画しています
運営しているYouTubeチャンネルで、ご相談やご質問を募集しています。動画のコメントやお問い合わせページからお気軽にご相談をお寄せください。