【ExcelVBA・マクロ】Type…End Type(ユーザー定義型)の使い方|複数の情報をひとまとめにする方法【コピペOK】

ExcelVBA

ExcelVBAでプログラムを組んでいると、「氏名」「年齢」「部署」のように、種類の異なる複数の情報をひとまとめにして扱いたい場面が出てきます。変数をバラバラに宣言することもできますが、関連する情報が多くなるほどコードが読みにくくなってしまいます。

この記事では、複数のデータをひとつの「型」としてまとめられるType…End Type(ユーザー定義型)の使い方を、基本から配列・プロシージャでの活用方法まで解説します。

スポンサーリンク
スポンサーリンク

Type…End Typeとは

Type…End Typeは、名前も型も異なる複数の変数を、ひとつの独自データ型としてまとめて定義できる機能です。他のプログラミング言語でいう「構造体」に近いイメージです。

例えば「社員情報」を扱いたい場合、氏名(文字列)・年齢(数値)・入社日(日付)のように種類が異なるデータを、Dimでバラバラに宣言する代わりに、ひとつの型としてまとめられます。

基本の書き方

' 標準モジュールの先頭(宣言セクション)に記述
Type Employee
    Name As String
    Age As Integer
    HireDate As Date
End Type

Type 型名 から End Type までの間に、まとめたい項目(メンバー)を メンバー名 As データ型 の形で並べます。定義した型は、標準モジュールの他のプロシージャから通常の型(StringやLongなど)と同じように使えます。

変数として使う

定義したユーザー定義型は、Dimで通常の変数と同じように宣言し、.(ドット)でメンバーにアクセスします。

Sub UseEmployeeType()

    Dim emp As Employee

    emp.Name = "山田太郎"
    emp.Age = 32
    emp.HireDate = DateSerial(2018, 4, 1)

    MsgBox emp.Name & "さん(" & emp.Age & "歳)" & vbCrLf & _
           "入社日:" & Format(emp.HireDate, "yyyy/mm/dd")

End Sub

emp.Nameemp.Ageのように、オブジェクトのプロパティと同じ感覚で各項目にアクセスできるのがポイントです。

配列と組み合わせて複数件のデータを扱う

ユーザー定義型は、配列と組み合わせることで真価を発揮します。例えば複数人の社員データを、それぞれ別の配列で管理するとコードが煩雑になりますが、ユーザー定義型の配列にすれば1つの配列でまとめて管理できます。

Sub UseEmployeeArray()

    Dim emps(1 To 3) As Employee
    Dim i As Long

    emps(1).Name = "山田太郎"
    emps(1).Age = 32
    emps(1).HireDate = DateSerial(2018, 4, 1)

    emps(2).Name = "佐藤花子"
    emps(2).Age = 27
    emps(2).HireDate = DateSerial(2021, 4, 1)

    emps(3).Name = "鈴木一郎"
    emps(3).Age = 45
    emps(3).HireDate = DateSerial(2005, 10, 1)

    For i = LBound(emps) To UBound(emps)
        Debug.Print emps(i).Name & " / " & emps(i).Age & "歳 / " & _
                     Format(emps(i).HireDate, "yyyy/mm/dd")
    Next i

End Sub

イミディエイトウィンドウに3人分の情報がまとめて出力されます。社員が増えても配列のサイズを変えるだけで対応でき、それぞれの人物ごとにまとまった情報として扱えるため、コードの見通しが良くなります。

セルのデータをユーザー定義型に読み込む

実務では、シート上の表データをユーザー定義型の配列に読み込んで処理することがよくあります。以下は、A列に氏名・B列に年齢・C列に入社日が入力された表を読み込む例です。

Sub LoadEmployeesFromSheet()

    Dim ws As Worksheet
    Dim emps() As Employee
    Dim lastRow As Long
    Dim i As Long

    Set ws = ThisWorkbook.Worksheets("社員一覧")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    ReDim emps(1 To lastRow - 1)

    For i = 1 To lastRow - 1
        emps(i).Name = ws.Cells(i + 1, "A").Value
        emps(i).Age = ws.Cells(i + 1, "B").Value
        emps(i).HireDate = ws.Cells(i + 1, "C").Value
    Next i

    ' 30歳以上の社員だけを抽出して表示
    For i = LBound(emps) To UBound(emps)
        If emps(i).Age >= 30 Then
            Debug.Print emps(i).Name & "(" & emps(i).Age & "歳)"
        End If
    Next i

End Sub

このように、シートから読み込んだ時点で「1行=1レコード」として扱えるため、条件で絞り込んだり並べ替えたりする処理がとても書きやすくなります。

ユーザー定義型をメンバーに持つ入れ子構造

ユーザー定義型の中に、別のユーザー定義型をメンバーとして持たせることも可能です。例えば「住所」を独立した型にして、社員情報の中に含めることができます。

Type Address
    PostalCode As String
    Prefecture As String
    City As String
End Type

Type EmployeeDetail
    Name As String
    Age As Integer
    HomeAddress As Address
End Type

Sub UseNestedType()

    Dim emp As EmployeeDetail

    emp.Name = "田中次郎"
    emp.Age = 29
    emp.HomeAddress.PostalCode = "150-0001"
    emp.HomeAddress.Prefecture = "東京都"
    emp.HomeAddress.City = "渋谷区"

    MsgBox emp.Name & "さんの住所:" & vbCrLf & _
           emp.HomeAddress.PostalCode & " " & _
           emp.HomeAddress.Prefecture & emp.HomeAddress.City

End Sub

emp.HomeAddress.Prefectureのように、ドットを重ねて入れ子になったメンバーにアクセスできます。関連する情報をグループ化して整理したい場合に便利な書き方です。

プロシージャの引数としてユーザー定義型を渡す

ユーザー定義型は、Subプロシージャの引数としてそのまま渡すこともできます。関連するデータをまとめて渡せるので、引数の数を減らしてシンプルなコードにできます。

Sub ShowEmployeeInfo(ByRef emp As Employee)
    Debug.Print emp.Name & "さんは" & emp.Age & "歳です"
End Sub

Sub CallShowEmployeeInfo()

    Dim emp As Employee
    emp.Name = "高橋美咲"
    emp.Age = 24

    Call ShowEmployeeInfo(emp)

End Sub

引数として渡す際は、既定でByRef(参照渡し)になります。値渡し(ByVal)にしたい場合は明示的にByValを指定してください。

Enum(列挙型)との違い

似たような機能に「Enum(列挙型)」がありますが、役割が異なります。

  • Enum:あらかじめ決まった選択肢(定数)に名前を付けるための機能。例:曜日、ステータス区分など
  • Type:種類の異なる複数のデータをひとつにまとめるための機能。例:氏名+年齢+入社日のようなレコード情報

「決まった選択肢から選ぶ」ならEnum、「複数の異なる情報をワンセットで扱う」ならTypeと使い分けるとよいでしょう。

使用時の注意点

Type…End Typeを使う際は、以下の点に注意してください。

  • 宣言場所:標準モジュールの宣言セクション(先頭、プロシージャの外側)に記述する必要があります。プロシージャの中には書けません。
  • Publicにする場合:クラスモジュールやユーザーフォームから参照したい場合は、標準モジュールでPublic Type 型名のようにPublicを付けて宣言します。
  • オブジェクト型は不可:メンバーにRangeやWorksheetなどのオブジェクト型を含めることはできません。オブジェクトを扱いたい場合はクラスモジュールの利用を検討してください。

まとめ

Type…End Typeを使うと、種類の異なる複数のデータをひとつのまとまりとして扱えるようになり、特に配列やシートからの一括読み込みと組み合わせたときにコードの見通しが大きく改善します。

  • 標準モジュールの宣言セクションで Type ~ End Type を定義する
  • 変数名.メンバー名 でアクセスする
  • 配列やプロシージャの引数と組み合わせることで実務データの管理がしやすくなる
  • 選択肢を扱うEnumとは役割が異なるので使い分ける

複数の関連データをまとめて扱いたい場面に出会ったら、ぜひType…End Typeを活用してみてください。

スポンサーリンク
スポンサーリンク
ExcelVBA
シェアする
いがぴをフォローする

コメント

タイトルとURLをコピーしました