ExcelVBA入門第11回 スコープ(適用範囲)

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変数は自分の村から出ないので、他の村でも同じ名前の小人さんが居たりします。特に、上記のようなループで使うijなどの変数は、あちこちの村に居ますが、同じ名前でも別の小人さんです。

モジュールの中で使える、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 はあまり多用しないほうが良いとされています。

できるだけ小さな範囲のスコープでプログラミングをすることということは、「誤作動を防ぐ」「安全性を高める」という意味になりますので、慣れてきたらぜひ意識してみてください。

公開日:2017/04/13

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)