変数と配列
・静的変数
・動的配列
・オブジェクト変数
・ユーザー定義型
【ここでのポイント】
プログラミング言語の変数としての意義は大きいのですが、
かといって、VBAにおいて頻繁に使うものでもなければ、無くてはならないものでもありません。
こういうものがあるのだということだけ覚えれば十分でしょう。
VBA開発において必須であり、応用は無限にありVBAになくてはならないものです。
ベーシックに配列はなかったのに、いきなり動的配列として項目に上がっています。
この意図が少々腑に落ちませんが、
公式テキストでも静的変数から説明されているので、まずは配列とは何かから学んでください。
そして、ReDimは試験に必ず出題されるはずなので、ここはしっかり覚えて下さい。
VBAの基本なので、本来は簡単な使い方くらいはベーシックでやっておいた方が良いとさえ思うものです。
使い方自体は簡単で、変数宣言の型指定とSetステートメントだけです。
ただし、プロパティ・メソッドの戻り型を意識しなければならない点は少し難しいかもしれません。
プログラミング言語の機能としては極めて重要なものです。
VBA開発での高機能なマクロ作成では、これが使えるかどうかで開発効率が大きく変わってくるものです。
とはいえ、覚えることはTypeステートメントと、ユーザー定義型の変数の使い方だけになります。
文法的な記述方法だけ覚えておけば、試験対策としては問題ないでしょう。
静的変数
プロシージャ内でDimステートメントで宣言した変数の値は、プロシージャが終了すると失われてしまいます。
プロシージャを連続で起動したり、連続でCallしても、変数は新たに用意されるため値は残りません。
つまり、モジュールがリセットされると静的変数もリセットされます。
Endステートメントが実行されると静的変数は失われます。
静的という言葉の意味
このくらいの意味で理解してください。
変数の静的割り当て、一度割り当てたらそれを使う。
変数の動的割り当て、毎回新たに割り当てる。
静的変数は、
Staticステートメントで宣言します。
プロシージャ レベルで使用します。
そこで、
通常の変数として、数値(IntegerやLong)、文字列(String)
これらを静的変数として宣言する記述と、その使い方、動作結果について説明します。
その違いは、プロシージャの外部に変数を公開しているかどうかになります。
モジュールレベル変数は、他のプロシージャによって書き換えられますが、
静的変数は、他のプロシージャの影響を受けません。
つまり、
静的変数は、宣言したプロシージャだけで使えるモジュールレベル変数と考えても良いでしょう。
Option Explicit
Private i1 As Long
Sub sample1()
Call sample2
Call sample2
End Sub
Sub sample2()
Static i2 As Long
i1 = i1 + 1
i2 = i2 + 1
MsgBox "i1:" & i1 & vbLf & "i2:" & i2
End Sub
このsampleを何度か実行して確認してください。
何度か実行したら、今度は「リセット」して再度実行してみて下さい。
恐らく出題されるとしても、Dim宣言した変数との動作違いや、
静的変数について説明文の正否くらいではないかと思います。
動的配列
配列の概念
集合住宅やアパートにたとえられますが、
要は、変数の箱を複数つなげたものと理解すれば良いでしょう。
結果として、複数の値をいれられるのが配列という事になります。
通常の変数が、1つの変数に1つの値を格納している点で大きく異なっています。
配列のインデックス番号(配列内の位置)を指定することで、個々の要素を参照することもできます。
(Option Baseで変更可能ですが、使うべきではありませんし試験にも出ないでしょう)
VBA内で、必要に応じて箱の数を変更する場合があります。
箱の数を固定せずVBAで動的に変更するのを、動的配列と呼びます。
静的配列
上記の宣言で、11個要素を持つ 1次元の配列を定義したことになります。
Sub sample()
Dim MyArray(10) As Long
Dim i As Long
For i = 0 To 10
MyArray(i) = i
Next i
End Sub
多次元配列
Sub sample()
Dim MyArray(10, 5) As Long
Dim i As Long, j As Long
For i = 0 To 10
For j = 0 To 5
MyArray(i, j) = Cells(i + 1, j + 1)
Next i
Next i
End Sub
上記では、セル範囲A1~F11を配列に入れています。
要素の下限の変更
このようにした方が、理解しやすく、また、記述もしやすいでしょう。
動的配列
実行時点で要素数を増減できるのが、動的配列になります。
プロシージャ レベルで使用します。
Preserve |
省略可能です。 |
varname |
必ず指定します。 |
subscripts |
必ず指定します。 |
type |
省略可能です。 |
キーワード Preserve を指定した場合、変更できるのは、動的配列の最後の次元のサイズに限られます。
つまり、
キーワードPreserveを使用した場合、動的配列のサイズを変更するために変えられるのは、添字の上限だけです。
添字の下限を変更しようとすると、エラーが発生します。
数値変数(Integer,Long)は 0 に、
可変長文字列(String)は長さ 0 の文字列 ("") に、
固定長文字列には 0 が埋められ、
バリアント型 (Variant) 変数は Empty値に初期化されます。
要素数の変更について
ReDim MyArray(10, 10)
↓
ReDim MyArray(10)
↓
ReDim MyArray(10, 10)
このように、Redimで次元も要素数も変更できます。
ReDim MyArray(10, 10)
↓
ReDim Preserve MyArray(10, 11)
↓
ReDim Preserve MyArray(11, 11)
Preserveを指定することで、値がそのまま残ります。
Preserveを指定した場合は、動的配列の最後の次元のサイズのみ変更可能で、
それより上位の次元は変更できません、エラーとなります。
配列で必要となるVBA関数とステートメント
arrayname | 必ず指定します。 配列変数の名前です。 変数の標準的な名前付け規則に従って指定します。 |
dimension | 省略可能です。 バリアント型 (内部処理形式 Long の Variant) の値を指定します。 添字の最小値を調べる対象となる配列の次元を示す整数を指定します。 最初の次元なら 1、2 番目の次元なら 2、というように指定します。 引数 dimension を省略すると、1 が指定されたものと見なされます。 |
UBound 関数
arrayname | 必ず指定します。 配列変数の名前です。 変数の標準的な名前付け規則に従って指定します。 |
dimension | 省略可能です。 バリアント型 (内部処理形式 Long の Variant) の値を指定します。 添字の最小値を調べる対象となる配列の次元を示す整数を指定します。 最初の次元なら 1、2 番目の次元なら 2、というように指定します。 引数 dimension を省略すると、1 が指定されたものと見なされます。 |
使用例.
For i = LBound(MyArray, 1) To UBound(MyArray, 1)
For j = LBound(MyArray, 2) To UBound(MyArray, 2)
MyArray(i, j) = 0
Next j
Next i
上記では、2次元配列MyArrayの全次元の全要素に0を入れています。
Array 関数
引数 arglist には、値のリストをカンマ (,) で区切って指定します。
引数 arglist を指定しない場合は、長さ 0 の配列が作成されます。
Dim MyArray
MyArray = Array(10, 20, 30)
この結果、MyArrayは、
LBound(MyArray)は0、UBound(MyArray)は2となります。
IsArray 関数
それ以外の場合は、偽 (False) を返します。
IsArray 関数は、特に配列を含むバリアント型 (Variant) の式 に有効です。
Join 関数
sourcearray | 必ず指定します。 結合する文字列を含む 1 次元配列を指定します。 |
delimiter | 省略可能です。戻り値となる文字列を区切るのに使用する文字を指定します。 省略すると、スペース (" ") が使用されます。 引数 delimiter が長さ 0 の文字列 (") である場合は、リスト内のすべての項目が区切り文字なしで連結されます。 |
Filter 関数
sourcearray |
必ず指定します。 |
match |
必ず指定します。 |
include |
省略可能です。 |
compare |
省略可能です。 |
引数 sourcearray 内で引数 match に一致する文字列がなかった場合は、Filter 関数は空の配列を返します。
引数 sourcearray が Null 値であるか、1 次元配列でない場合は、エラーになります。
Filter 関数が返す配列は、一致した項目数分だけの要素が含まれています。
Erase ステートメント
静的数値配列 | 要素はすべて 0 に設定されます。 |
静的文字列配列 (可変長) | 要素はすべて長さ 0 の文字列 (") に設定されます。 |
静的文字列配列 (固定長) | 要素はすべて 0 に設定されます。 |
静的バリアント型 (Variant) 配列 | 要素はすべて Empty 値に設定されます。 |
ユーザー定義型配列 | 各要素は、別個の変数として設定されます。 |
オブジェクト配列 | 要素はすべて特別な値 Nothing に設定されます。 |
LBoundとUBound以外は出題されないかもしれませんが、
実務で配列を使う上で、覚えておくべき関数として紹介しています。
試験対策としては、
Redim
Preserve
LBound
UBound
これらをしっかり覚えておけば良いでしょう。
オブジェクト変数
変数のデータ型に、
Object ・・・ オブジェクト型
があります。
数値や文字ではなく、オブジェクトを入れる変数がオブジェクト変数です。
ブックもシートもセルも、これらは全てオブジェクトです。
総称オブジェクト型とも言います。
さらに固有のオブジェクトに対応した、データ型もあります。
Workbook
Worksheet
Range
これらは、それぞれ、
Workbookオブジェクト
Worksheetオブジェクト
Rangeオブジェクト
のデータ型です。
これは、Fontオブジェクトのデータ型になります。
とりあえず、Workbook、Worksheet、Range、この3つを覚えれば良いでしょう。
Variant(バリアント型) > Object(総称オブジェクト型) > 固有オブジェクト型
このような関係になります、つまり、
Objectは、オブジェクトなら何でも入る
個別のオブジェクト型は、そのオブジェクトのみ
オブジェクトの参照、つまり、アドレスを変数にいれるということです。
オブジェクト変数を意図的に破棄する場合は、Nothingを代入します。
メソッドの戻り値をオブジェクト変数に代入
この時の戻り値には型があります。
Dim wb As Workbook
Set wb = Workbooks.Open("test.xlsx")
ブックOpenでは、Openしたブックが戻されますので、それをSetステートメントで変数に代入しています。
Dim sht As Worksheet
Set sht = Worksheets.Add
シートAddでは、挿入されたシートが戻されますので、それをSetステートメントで変数に代入しています。
Dim sht As Worksheet
Set sht = Worksheets(1).Copy(After:=Worksheets(1))
これはエラーとなります、Copyメソッドは値を戻しません。
とはいえ、
試験としては上記の例を知っていれば十分だと思います。
使用例
Dim ws As Worksheet
Set ws =
Worksheets("シート名")
ws.Cells(1, 1) =
1
これは、
Worksheets("シート名").Cells(1, 1) = 1
これと同じ事になります。
Range("A1").Font.Bold = True
Range("A1").Font.Color =
vbRed
Range("A1").Font.Size = 12
これは、
Dim MyRange as Range
Set MyRange = Range("A1")
MyRange.Font.Bold = True
MyRange.Font.Color = vbRed
MyRange.Font.Size =
12
このように書き直す事が出来ます。
さらに以下のように書くこともできます。
Dim MyRange As Range
Dim myFont As Font
Set MyRange = Range("A1")
Set myFont = MyRange.Font
With myFont
.Bold = True
.Color = vbRed
.Size = 12
End With
試験対策としては、このVBAコードが読み書きできるようになってください。
Withステートメントと組み合わせたVBAコードをすんなり読めるようになっておいてください。
注意
Setステートメントを使う事で、オブジェクトへの参照が変数に代入されます。
ただし、Setステートメントで代入する変数の型が違う場合はエラーとなります。
VBAコード | 正否 | 理由 |
Dim myRange As Range Set myRange = Range("A1") |
○ | Range型変数に、SetステートメントでRangeオブジェクトを代入 |
Dim myRange As Range myRange = Range("A1") |
× | Setステートメントを使わずに、オブジェクト型変数へ代入するとエラーとなります |
Dim mySheet As Worksheet Set mySheet = Workbooks(1).ActiveSheet |
○ | Worksheet型変数に、SetステートメントでActiveSheetを代入 |
Dim mySheet As Worksheet Set mySheet = Workbooks(1).Worksheets |
× | Worksheet型変数に、Worksheetsコレクションは代入できません |
Dim mySheet As Variant Set mySheet = Workbooks(1).Worksheets |
○ | Variant型変数なので、コレクションでも入れられます |
Dim mySheet As Worksheet Set mySheet = Range("A1") |
× | Worksheet型変数に、SetステートメントでRangeオブジェクトは代入できません |
Dim myRange Set myRange = Range("A1") |
○ | Variant型変数に、SetステートメントでRangeオブジェクトを代入 |
Dim myRange myRange = Range("A1") |
△ | Variant型変数に、セルの値を代入していることになります。 Setステートメントを使った時との違いを理解してください。 |
試験対策としては、
メソッドの戻り値と、最後の「注意」をしっかり覚えておけば良いでしょう。
ユーザー定義型
ユーザー定義型は、名前の通りユーザーが定義できるデータ型になります。
ユーザー定義型は、複数の異なるデータ型を入れる事が出来ます。
構造体は、オブジェクトとも言えます。
(プログラミング言語によっては、オブジェクトそのものです)
オブジェクトが、複数のデータ型の違うプロパティを持っていることと同様に考えてよいものです。
elementname [([subscripts])] As type
[elementname [([subscripts])] As type]
・・・
End Type
Public | 省略可能です。 すべてのプロジェクトのすべてのモジュールのどのプロシージャからも参照できるユーザー定義型を宣言するときに指定します。 |
Private | 省略可能です。 宣言が行われたモジュール内でのみ参照できるユーザー定義型を宣言するときに指定します。 |
varname | 必ず指定します。 宣言するユーザー定義型の名前です。 変数の標準的な名前付け規則に従って指定します。 |
elementname | 必ず指定します。 ユーザー定義型を構成する要素の名前です。 要素名は、変数の標準的な名前付け規則に従って指定します。 ただし、キーワードを使うこともできます。 |
subscripts | 省略可能です。 配列の要素の次元を指定します。 動的配列を宣言する場合は、かっこだけを指定します。 引数 subscripts の構文は次のとおりです。 [lower To] upper [,[lower To] upper] . . . 引数 lower を省略すると、配列の添字の最小値は Option Base ステートメントによって制御されます。 Option Base ステートメントが記述されていない場合は、添字の最小値は 0 になります。 |
type | 必ず指定します。 要素のデータ型を指定します。 バイト型 (Byte)、ブール型 (Boolean)、整数型 (Integer)、長整数型 (Long)、通貨型 (Currency)、単精度浮動小数点数型 (Single)、倍精度浮動小数点数型 (Double)、日付型 (Date)、文字列型 (String) (可変長の場合は String、固定長の場合は String * length)、オブジェクト型 (Object)、バリアント型 (Variant)、ほかのユーザー定義型、オブジェクトの種類のいずれかを指定できます。 |
Type ステートメントは、モジュール レベルでのみ使用できます。
つまり、Type ステートメントは型(LongやString等と同様)をユーザーが定義しているということです。
ユーザー定義型の変数全体を、直接バリアント型 (Variant) に代入できません。
ユーザー定義型の使い方
Private
Public
モジュールレベルで宣言してある、ユーザー定義型の名前を指定します。
Type type社員
番号 As Long
氏名 As String
所属 As String
住所 As String
電話 As String
End Type
Sub sample()
Dim 社員 As type社員
社員.番号 = 1101
社員.氏名 = "名前"
・・・
End Sub
ユーザー定義型の変数を使う時、
ピリオドまで入れると、ユーザー定義型の要素が候補表示されます。
ユーザー定義型を自在かつ適切に使えるようになるには、相当の経験が必要になります。
Typeステートメントをモジュールレベルで宣言する
ユーザー定義型の変数名と要素名をピリオドでつなぐ
このあたりを把握しておけば大丈夫でしょう。
【業務改善の実務】
もちろん使えるなら使っても構いませんが、無理に使うようなものではありません。
これは迷い使えるようにならなければなりません。
メソッドの戻り値は、
Setステートメントで変数に代入するか、
Withステートメントで受けるようにVBAを書くと、記述がすっきりして読みやすいVBAコードになります。
セル範囲を変数に入れて処理できるようになれば、マクロが格段に高速化されます。
大量データを扱うVBAを作成する場合は、絶対に必要になってきますので、ぜひしっかり覚えて下さい。
これを適切に使えるようになるには、相応の時間がかかるかもしれません。
しかし、これを使う事のメリットも大きいので、簡単な使い方から徐々に覚えて行ってください。
【本サイト内の関連ページ】
第111回.静的配列
第52回.オブジェクト変数とSetステートメント
配列の使い方について
VBAエキスパート公式テキスト
こちらは必須として購入した方が良いでしょう。
ちょっと高いなーとは思いますが、
書籍を購入することで、学習用データが提供されています。
・サンプルブック
・VBAエキスパート模擬問題
これらが使えるようになります。
このシリーズでは、テキストを読みながら学習していることを前提とします。
同じテーマ「VBAエキスパート対策」の記事
プロシージャ
イベント
ステートメント(スタンダード)
関数
エラーへの対処
APIとOLEオートメーション
変数と配列
レジストリの操作
ファイルの操作
ユーザーフォームとメニューの操作
VBAスタンダード試験対策まとめ
新着記事NEW ・・・新着記事一覧を見る
TRIMRANGE関数(セル範囲をトリム:端の空白セルを除外)|エクセル入門(2024-08-30)
正規表現関数(REGEXTEST,REGEXREPLACE,REGEXEXTRACT)|エクセル入門(2024-07-02)
エクセルが起動しない、Excelが立ち上がらない|エクセル雑感(2024-04-11)
ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.繰り返し処理(For Next)|VBA入門
3.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
4.変数宣言のDimとデータ型|VBA入門
5.RangeとCellsの使い方|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.セルのクリア(Clear,ClearContents)|VBA入門
8.メッセージボックス(MsgBox関数)|VBA入門
9.条件分岐(Select Case)|VBA入門
10.ブック・シートの選択(Select,Activate)|VBA入門
- ホーム
- マクロVBA入門編
- VBAエキスパート対策
- 変数と配列
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。