Enum(列挙型)
VBA でコードを書く際、列番号や状態を表す数値をハードコードしてしまうことは少なくありません。こうしたマジックナンバーはコードの可読性を大きく下げ、保守を困難にします。そんな問題を解決するのが Enum(列挙型) です。
Enum を使うと、関連する数値定数をグループ化し、意味のある名前で扱えるようになります。さらに、IntelliSense(入力補完)による候補表示も利用できるため、入力ミスの防止にもつながります。
この記事では、Enum の基本的な構文から、列番号管理やフラグ演算といった実践的な活用方法まで詳しく解説します。
Enum が必要になるシチュエーション
実務では、以下のような場面で Enum が威力を発揮します:
- ワークシートの列番号管理: 各列に意味のある名前を付け、列の挿入・削除に柔軟に対応する
- 処理の状態管理: 「未処理」「処理中」「完了」「エラー」などのステータスを定数で管理する
- 関数の引数やオプション: 関数に渡す設定値を、数値ではなく名前で指定する
- 設定値の一元管理: 色番号、シート番号、カテゴリなど、関連する定数をまとめて管理する
Enum の基本的な構文
Enum の宣言
Enum は、Enum ~ End Enum の間にメンバー(要素)を列挙して宣言します。宣言はモジュールの宣言セクション(プロシージャの外側)に記述します。
Enum Fruit
Apple = 1
Banana = 2
Orange = 3
End Enum
Sub ShowFruit()
Dim f As Fruit
f = Fruit.Apple
Debug.Print f ' => 1
End Sub
Enum はプロシージャ (Sub / Function) の内部では宣言できません。必ずモジュールの先頭、プロシージャの外側に記述してください。
値の自動採番
Enum の最大の特徴の一つが、値の自動採番です。最初の要素に値を指定すれば、以降の要素は自動的に 1 ずつ増加した値が割り当てられます。
Enum TableColumn
番号 = 1
名前 ' => 2
住所 ' => 3
電話番号 ' => 4
商品 ' => 5
End Enum
最初の要素の値を省略した場合は、0 から始まります。
Enum Color
Red ' => 0
Green ' => 1
Blue ' => 2
End Enum
ワークシートの列番号として Enum を使う場合、Excel の列番号は 1 から始まるため、最初の要素に = 1
を明示的に指定しましょう。
途中から値を指定する
自動採番の途中で値を明示的に指定することも可能です。指定された値以降は、その値を基準に再び 1 ずつ増加します。
Enum Priority
Low = 1 ' => 1
Medium ' => 2
High = 10 ' => 10
Critical ' => 11
End Enum
Enum のスコープ
Public と Private
Enum には Public(公開)と Private(非公開)の 2 つのスコープを指定できます。
' すべてのモジュールから参照可能
Public Enum Status
Pending = 0
Processing = 1
Completed = 2
End Enum
' このモジュール内でのみ参照可能
Private Enum InternalCode
CodeA = 100
CodeB = 200
End Enum
スコープを省略した場合は Public として扱われます。これは変数 (Dim) や定数 (Const)
の省略時の挙動と異なるため注意してください。
定義場所のベストプラクティス
Enum はどこに定義しても 列挙型名.要素名 の形式でアクセスしますが、以下の使い分けが推奨されます:
| 用途 | 定義場所 | スコープ |
|---|---|---|
| プロジェクト全体で使用 | 標準モジュール | Public |
| 特定モジュール内のみ | 標準モジュール | Private |
| クラスの内部定数 | クラスモジュール | Private |
Sheet1 やクラスモジュールに定義した Enum であっても、Sheet1.Status.Completed
のようなオブジェクト経由のアクセスはできません。常に Status.Completed
のように列挙型名から直接アクセスします。
Enum の使い方
値の参照
Enum の値を参照するには、列挙型名.要素名 の形式を使います。列挙型名を省略して要素名だけでもアクセスできますが、明示的に列挙型名を付ける方が可読性が高くなります。
Enum Fruit
Apple = 1
Banana = 2
Orange = 3
End Enum
Sub ShowValues()
' 推奨: 列挙型名を付ける
Debug.Print Fruit.Apple ' => 1
' 省略も可能(ただし非推奨)
Debug.Print Apple ' => 1
End Sub
列挙型名を付けて参照すると、IntelliSense(入力補完)で候補が表示されるため、入力ミスを防ぐことができます。
変数の型として使用
Enum は変数や引数の型として使用できます。型として指定すると、その Enum に定義された値のみを受け取ることが期待されるため、コードの意図が明確になります。
Enum OrderStatus
Pending = 0
Shipped = 1
Delivered = 2
Cancelled = 3
End Enum
Sub UpdateOrder(ByVal status As OrderStatus)
Select Case status
Case OrderStatus.Pending
Debug.Print "注文は受付中です"
Case OrderStatus.Shipped
Debug.Print "商品は発送済みです"
Case OrderStatus.Delivered
Debug.Print "商品はお届け済みです"
Case OrderStatus.Cancelled
Debug.Print "注文はキャンセルされました"
End Select
End Sub
Sub TestOrder()
' Enum を引数に渡す
Call UpdateOrder(OrderStatus.Shipped)
' => 商品は発送済みです
End Sub
Enum 型の引数には、定義された要素以外の数値も代入できてしまいます。VBA の Enum
は厳密な型安全性を持たないため、必要に応じて Select Case の Case Else
でバリデーションを行いましょう。
関数の戻り値として使用
関数の戻り値にも Enum 型を指定できます。VBA の組み込み関数 MsgBox の戻り値 VbMsgBoxResult がその代表例です。
Enum ValidationResult
Valid = 0
EmptyValue = 1
InvalidFormat = 2
OutOfRange = 3
End Enum
Function ValidateAge(ByVal age As String) As ValidationResult
' 空チェック
If Len(age) = 0 Then
ValidateAge = ValidationResult.EmptyValue
Exit Function
End If
' 数値チェック
If Not IsNumeric(age) Then
ValidateAge = ValidationResult.InvalidFormat
Exit Function
End If
' 範囲チェック
If CLng(age) < 0 Or CLng(age) > 150 Then
ValidateAge = ValidationResult.OutOfRange
Exit Function
End If
ValidateAge = ValidationResult.Valid
End Function
Sub TestValidation()
Dim result As ValidationResult
result = ValidateAge("abc")
Select Case result
Case ValidationResult.Valid
Debug.Print "有効な値です"
Case ValidationResult.EmptyValue
Debug.Print "値が入力されていません"
Case ValidationResult.InvalidFormat
Debug.Print "数値を入力してください"
Case ValidationResult.OutOfRange
Debug.Print "0〜150 の範囲で入力してください"
End Select
' => 数値を入力してください
End Sub
実践的な活用例
列番号の管理
Enum の最も代表的な活用例が、ワークシートの列番号管理です。Enum の自動採番機能と列番号の連番は非常に相性が良く、列の挿入・削除にも柔軟に対応できます。
以下のようなワークシートを操作する場合を考えます:
| 社員番号 | 氏名 | 部署 | 入社日 | 給与 |
|---|---|---|---|---|
| E001 | 田中太郎 | 開発部 | 2020/04/01 | 350000 |
| E002 | 佐藤花子 | 営業部 | 2019/08/15 | 380000 |
Enum Col社員マスタ
社員番号 = 1
氏名
部署
入社日
給与
End Enum
Sub ProcessEmployeeData()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("社員マスタ")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, Col社員マスタ.社員番号).End(xlUp).Row
Dim i As Long
For i = 2 To lastRow
' 列番号にマジックナンバーを使わない
Dim empId As String
empId = ws.Cells(i, Col社員マスタ.社員番号).Value
Dim empName As String
empName = ws.Cells(i, Col社員マスタ.氏名).Value
Dim salary As Long
salary = ws.Cells(i, Col社員マスタ.給与).Value
Debug.Print empId & " : " & empName & " : " & Format(salary, "#,##0") & "円"
Next i
End Sub
「部署」と「入社日」の間に「役職」列が追加された場合、Enum に 役職 を 1
行追加するだけで対応できます。以降の要素は自動的に再採番されるため、コード内の修正は不要です。
複数シートの列管理
複数のシートを操作する場合は、シートごとに Enum を定義すると管理が容易になります。
Enum Col商品マスタ
商品コード = 1
商品名
カテゴリ
単価
在庫数
End Enum
Enum Col受注データ
受注番号 = 1
受注日
顧客名
商品コード
数量
金額
End Enum
Sub CreateOrderSummary()
Dim wsProduct As Worksheet
Set wsProduct = ThisWorkbook.Sheets("商品マスタ")
Dim wsOrder As Worksheet
Set wsOrder = ThisWorkbook.Sheets("受注データ")
' 受注データからデータを取得
Dim orderNo As String
orderNo = wsOrder.Cells(2, Col受注データ.受注番号).Value
Dim productCode As String
productCode = wsOrder.Cells(2, Col受注データ.商品コード).Value
' 商品名は商品マスタから参照
Debug.Print "受注番号: " & orderNo & " / 商品コード: " & productCode
End Sub
ビット演算によるフラグ管理
Enum の値を 2 のべき乗(1, 2, 4, 8…)で定義すると、ビット演算を使って複数の状態を 1 つの変数で管理できます。
Enum Permission
None = 0 ' 権限なし
Read = 1 ' 読み取り (0001)
Write = 2 ' 書き込み (0010)
Execute = 4 ' 実行 (0100)
Admin = 8 ' 管理者 (1000)
End Enum
Sub CheckPermission()
' Or 演算子で複数の権限を組み合わせる
Dim userPerm As Permission
userPerm = Permission.Read Or Permission.Write ' => 3 (0011)
' And 演算子で権限を持っているか判定する
If (userPerm And Permission.Read) = Permission.Read Then
Debug.Print "読み取り権限: あり"
End If
If (userPerm And Permission.Execute) = Permission.Execute Then
Debug.Print "実行権限: あり"
Else
Debug.Print "実行権限: なし"
End If
' => 読み取り権限: あり
' => 実行権限: なし
End Sub
2 のべき乗でフラグを定義すると、各フラグが 2 進数の異なるビット位置に対応します。Or
演算で複数のフラグを合成し、And 演算で個別のフラグの有無を判定できます。VBA の組み込み定数
vbYesNoCancel なども同様の仕組みです。
Const との比較
VBA で定数を管理する方法として、Enum のほかに Const ステートメントがあります。それぞれの特徴を比較します。
| 機能 | Enum | Const |
|---|---|---|
| データ型 | Long(数値のみ) | すべての型 |
| グループ化 | ○ 可能 | × 個別に宣言 |
| IntelliSense | ○ 候補表示あり | × 候補表示なし |
| 自動採番 | ○ 連番が自動割り当て | × 手動で指定 |
| 型としての利用 | ○ 引数・変数の型に使用可能 | × 型として使用不可 |
| 文字列の定義 | × 不可 | ○ 可能 |
| 小数の定義 | × 不可(整数のみ) | ○ 可能 |
' Const で列番号を管理する場合
Private Const COL_EMPLOYEE_ID As Long = 1
Private Const COL_NAME As Long = 2
Private Const COL_DEPARTMENT As Long = 3
Private Const COL_HIRE_DATE As Long = 4
Private Const COL_SALARY As Long = 5
' ↓ Enum を使えばよりシンプルに書ける
Enum ColEmployee
EmployeeId = 1
Name
Department
HireDate
Salary
End Enum
数値(特に連番) の定数をグループで管理するなら Enum、文字列やブール値、小数
の定数を定義するなら Const を使いましょう。
注意点
Enum は整数型(Long)のみ
Enum で定義できる値は Long 型の整数のみです。文字列や小数は使用できません。
' これはエラーになる
Enum InvalidEnum
Name = "田中" ' エラー: 文字列は使用不可
Rate = 3.14 ' エラー: 小数は使用不可
End Enum
文字列の定数をグループ化したい場合は、標準モジュールに Public Const を並べて擬似的に Enum のように管理する方法があります。
要素名の重複に注意
異なる Enum であっても、Public スコープで同じ要素名を定義するとコンパイルエラーになります。
' コンパイルエラーになる例
Public Enum Fruit
Apple = 1
Orange = 2
End Enum
Public Enum Color
Red = 1
Orange = 2 ' エラー: Fruit.Orange と名前が衝突する
End Enum
要素名の衝突を避けるために、プレフィックスを付ける(例: clrOrange、frtOrange)か、片方を
Private にするなどの工夫が必要です。
練習問題
まとめ
- Enum は、関連する数値定数をグループ化して管理するための VBA の機能
- 値の自動採番機能があり、連番の定数を簡潔に定義できる
- ワークシートの列番号管理に特に有効で、列の挿入・削除にも柔軟に対応できる
- IntelliSense による入力補完が利用でき、入力ミスを防止できる
- 変数や引数の型として使用でき、コードの意図を明確にできる
Constが文字列や小数に対応できるのに対し、Enum は Long 型の整数のみ- スコープ省略時は Public になる点、要素名の重複に注意が必要