日経PC 21 - 日経BP社 ビジネス マンのパソコン誌

このページの本文に進む

日経PC21サイト内リンクへ進む

日経パソコン オンライン
ホーム
ニュース
モバイル&スマートフォン
PC&Mac
DIY PC
周辺機器&カメラ
セキュリティ
クラウド
ソフトウエア
ビギナーズ
用語
日経BP社 パソコン情報
TRENDYnet
日経パソコン
日経PCビギナーズ
日経WinPC

エクセル(Excel)の便利な使いこなし方法を解説するWEBスペシャル

全460ページの「エクセル(Excel)大事典」を読めば“演算誤差の謎”がよくわかる!

エクセルVBA講座「変数のすべて」

第5回 変数の適用範囲(スコープ)

変数には適用範囲があります。適用範囲とは「Aというエリアで宣言した変数は、Bというエリアでは使えない」など「その変数はどこで使えるか」といった考え方(仕組み)です。この"変数の適用範囲"という考え方を理解するには、まずVBAにはどんな"エリア"があるかを理解しなければなりません。

マクロの記述エリア「モジュール」

マクロとは、Excelを自動実行させるための"命令書"です。その命令を記述できる場所のことを「モジュール」と呼びます。マクロはブック内に保存されますので、モジュールもブックごとに管理されています。エクセルVBAで利用できる一般的なモジュールは次の通りです。

・シートモジュール

シートごとに別々のモジュールが存在します。一般的に、ワークシート[Sheet1]のモジュール名は[Sheet1]になりますが、シート見出しに表示されるワークシート名とモジュール名は必ずしも一致しません。グラフシートにもモジュールがありますが、よく使われるのはワークシートのモジュールです。

・ブックモジュール

ブックに最初から用意されているモジュールです。ブックを開いたとき自動的に実行するマクロなどは、このブックモジュールに記述します。プロジェクトエクスプローラでは[ThisWorkbook]と表示されています。

・フォームモジュール

UserForm(フォーム)のモジュールです。UserFormを操作するマクロはここに記述します。UserFormを挿入すると使用できるようになります。

・標準モジュール

ワークシートやブックに属さない汎用的なモジュールです。VBEで[挿入]-[標準モジュール]を実行すると使用できるようになります。また、マクロ記録を実行すると自動的に標準モジュールが挿入されます。

エクセルVBAでは他にもクラスモジュールというモジュールがありますが、ここでは割愛します。クラスモジュールは、ユーザーが独自のクラスを定義するときに使用するモジュールです。

それぞれのモジュールは上図のようなイメージです。

1つのブックには、マクロを記述する場所(モジュール)が複数あるということだけ理解してください。

マクロの最小単位「プロシージャ」

1つの命令書(モジュール)には、複数の命令(マクロ)を記述できます。実行されるマクロは「Sub マクロ名」から始まり「End Sub」で終わります。このように、実行されるマクロの最小単位を「プロシージャ」と呼びます。

プロシージャには、Subで始まるSubプロシージャと、Functionで始まるFunctionプロシージャがありますが、ここではSubプロシージャを例に解説します。

変数の適用範囲(プロシージャ間)

まず、プロシージャ間での適用範囲について解説します。
 プロシージャの内部で宣言した変数は、宣言したプロシージャの中でしか使用できません

Sub Sample1()
   Dim buf As String  ''文字列型の変数を宣言する
   buf = "tanaka"    ''変数に"tanaka"という文字を入れる
End Sub

Sub Sample2()
   MsgBox buf     ''変数の値を表示する(←エラーになる)
End Sub

上のコードは、プロシージャ「Sample1」の中で変数bufを宣言しています。変数bufには"tanaka"という文字列を入れていますが、この変数bufを別のプロシージャ「Sample2」で参照することはできません。もちろん、変数内を参照できないだけでなく、次のように値を入れようとしてもエラーになります。

Sub Sample1()
   Dim buf As String   ''文字列型の変数を宣言する
End Sub

Sub Sample2()
   buf = "tanaka"   ''変数に"tanaka"という文字を入れる(←エラーになる)
   MsgBox buf     ''変数の値を表示する
End Sub

プロシージャの中で宣言した変数は、宣言したプロシージャの中でしか使用できません。このような変数を「ローカル変数」と呼びます。

しかし、ときには複数のプロシージャで同じ変数を使いたいこともあります。1つのモジュール内にあるすべてのプロシージャで同じ変数を使えるようにするには、モジュール内の「宣言セクション」で変数を宣言します。宣言セクションとは、モジュールの先頭から、最初のプロシージャまでの間です。

Dim buf As String    ''文字列型の変数を宣言する

Sub Sample1()
   buf = "tanaka"   ''変数に"tanaka"という文字を入れる
   Call Sample2     ''プロシージャ「Sample2」を実行する
End Sub

Sub Sample2()
   MsgBox buf     ''変数の値を表示する
End Sub

宣言セクションで宣言した変数は、宣言したモジュール内のすべてのプロシージャで使用できます。このような変数を「モジュールレベル変数」と呼びます。

変数の適用範囲(モジュール間)

上記は、1つのモジュール内での適用範囲について解説しました。今度は、複数のモジュール間で変数の適用範囲を考えてみましょう。

ここでは、標準モジュール「Module1」と、標準モジュール「Module2」を例にします。まず、モジュールの宣言セクションで宣言する「モジュールレベル変数」が他のモジュールで使用できるかどうかを検証してみましょう。Module1とModule2に、それぞれ次のようなコードを書きます。

Module1

Dim buf As String    ''文字列型のモジュールレベル変数を宣言する

Sub Sample1()
   buf = "tanaka"   ''変数に"tanaka"という文字を入れる
   Call Sample2     ''プロシージャ「Sample2」を実行する
End Sub

Module2

Sub Sample2()
   MsgBox buf     ''変数の値を表示する
End Sub

プロシージャ「Sample1」を実行すると、Module2のプロシージャ「Sample2」でエラーになります。

予想通り、モジュールレベル変数は、他のモジュールで使用できません。まず、この点を理解してください。では、すべてのモジュールで使用できる変数を宣言するときは、どうしたらいいのでしょう。それには「Public」という命令を使って変数を宣言します。

Module1

Public buf As String   ''文字列型のパブリック変数を宣言する

Sub Sample1()
   buf = "tanaka"    ''変数に"tanaka"という文字を入れる
   Call Sample2     ''プロシージャ「Sample2」を実行する
End Sub

Module2

Sub Sample2()
   MsgBox buf     ''変数の値を表示する
End Sub

今度は、Module1で宣言した変数bufを、Module2で使用できました。このように、すべてのモジュールで使用できる変数を「パブリック変数」と呼びます。

以上の特性を整理すると、下図のようになります。それぞれの変数は、宣言の違いにより矢印で結んだ場所で使用可能です。

変数は適用範囲を考えて宣言する

変数の適用範囲をまとめてみましょう。

・ローカル変数
プロシージャの内部で、Dimを使って宣言します。宣言したプロシージャだけで使えます

・モジュールレベル変数
モジュールの宣言セクションで、Dimを使って宣言します。宣言したモジュール内のすべてのプロシージャで使えます

・パブリック変数
モジュールの宣言セクションで、Publicを使って宣言します。すべてのモジュールの、すべてのプロシージャで使えます

もっとも広範囲で使える変数はパブリック変数です。複数のモジュールで構成される大規模なマクロでは必須です。モジュールがひとつしか存在しない小規模なマクロでは、どのプロシージャで何の変数を使うかを検討して、必要な変数だけをモジュールレベル変数として宣言します。ときどき次のような宣言を見かけますが、適切な使い方ではありません。

Dim i As Long, buf As String

Sub Sample1()
   For i = 1 To 10
     If Cells(i, 1) = "tanaka" Then buf = Cells(i, 1).Address
   Next i
   MsgBox buf
End Sub

Sub Sample2()
   For i = 1 To Worksheets.Count
     If Worksheets(i).Name = "合計" Then buf = Worksheets(i).Range("A1")
   Next i
   MsgBox buf
End Sub

Sample1とSample2では、どちらも変数iと変数bufを使っていますが、両者はまったく別の処理をしています。2つのプロシージャで同じような変数を使うからといって、これらの変数をモジュールレベル変数として宣言するのは間違っています。Sample1の変数iと変数bufはSample1内だけで完結し、Sample2で使用されることはありません。この場合、変数iと変数bufをモジュールレベルにする必要性がありません。次のように、それぞれプライベート変数として宣言しましょう。

Sub Sample1()
   Dim i As Long, buf As String
   For i = 1 To 10
     If Cells(i, 1) = "tanaka" Then buf = Cells(i, 1).Address
   Next i
   MsgBox buf
End Sub

Sub Sample2()
   Dim i As Long, buf As String
   For i = 1 To Worksheets.Count
     If Worksheets(i).Name = "合計" Then buf = Worksheets(i).Range("A1")
   Next i
   MsgBox buf
End Sub

モジュールレベル変数やパブリック変数は、手抜きをするために使う機能ではありません。

また、ローカル変数は、Subプロシージャが終了すると値がクリアされますが、モジュールレベル変数とパブリック変数はSubプロシージャが終了しても値がクリアされず、次に別のプロシージャを実行したときにも前の値を保持しています。こうした特性を正しく認識していないと、予期せぬバグを招く原因になりかねません。

別のプロシージャで値を使用する方法

モジュールレベル変数は、複数の異なるプロシージャ間で変数の値を共有したいときに使用します。しかし、別のプロシージャに値を引き渡すだけならモジュールレベル変数を使わなくても可能です。

Sub Sample1()
   Dim buf As String     ''文字列型の変数を宣言する
   buf = "tanaka"       ''変数に文字列"tanaka"を入れる
   Call Sample2(buf)     ''Sample2の引数として変数bufを引き渡す
End Sub

Sub Sample2(tmp As String) ''Sample2は1つの文字列を引数として受け取る
   MsgBox tmp        ''受け取った文字列を表示する
End Sub

値を引き渡す先のプロシージャ(Sample2)は、引数として1つの文字列を受け取るようにします。こうした使い方は、変数の機能というよりも、SubプロシージャやFunctionプロシージャの特性です。本当は、受け取った値を編集するケースに応じて「値渡し」や「参照渡し」などのテクニックが存在するのですが、そうした話はまた別の機会に詳解しましょう。

<< 前のページ| 5/11 |次のページ >>

↑ページの先頭へ←直前のページへ

日経PC.21がお薦めする日経BP社のサイト

日経BP書店