【VBA入門】構造体の使い方(宣言、初期化、引数、コピー、定数)

構造体って使っていますか?構造体とは、配列と同じようにデータをひとかたまりで扱うことができて便利です。

配列は同じ型のデータをひとかたまりで扱うことができますが、構造体は型の違うデータもひとかたまりで扱うことができます。構造体というとC言語がよく知られていますが、VBAでも構造体を扱うことができます。

この記事では、構造体について

  • 構造体とは
  • 構造体の使い方
  • といった基本的な内容から

  • 構造体を引数に指定する方法
  • 配列の要素に構造体を指定する
  • 構造体をコピーする方法
  • 構造体のメンバで定数を定義する方法
  • など応用的な内容についても解説していきます。

    今回は構造体について、使い方をわかりやすく解説します!

    目次

    構造体とは

    構造体とは、複数以上のデータをまとめて1つのかたまりにしたものです。まとめられたデータはフィールド(メンバ変数)と呼ばれ、型の違う変数をフィールドとすることができます。

    構造体はオブジェクトを生成して使用します。オブジェクトからフィールドを呼び出し、値を代入して使用します。

    なお、同じように複数のデータをまとめて1つのかたまりにしたものに配列があります。配列の場合は同じ型のデータしか1つのかたまりにできません。構造体は型の違うデータも1つのかたまりにできます。

    構造体の使い方

    構造体の使い方について宣言の方法、初期化の方法を順に説明していきます。

    構造体の宣言

    構造体を宣言する方法について説明します。

    構造体はTypeステートメントを使ってユーザー定義型を宣言します。下記のように記述します。

    Type 構造体名
        フィールド名1 As 型名
        フィールド名2 As 型名
        ・・・
    End Type

    構造体名というデータ型として定義されます。

    例えば以下のような記述になります。

    Type personalInfo
        name As String
        sex As String
        age As Integer
        add As String
        job As String
    End Type

    この例ではpersonalInfo型の構造体(ユーザー定義型)を宣言しています。

    構造体の初期化

    それでは構造体のオブジェクトを定義し、初期化する方法について説明します。

    以下のようにオブジェクトを生成します。

    Dim オブジェクト名 As 構造体名

    オブジェクトを定義したら、次のように記述してフィールドにアクセスします。

    オブジェクト名.フィールド名

    それではサンプルコードで確認しましょう。

    '構造体の宣言
    Type personalInfo
        name As String
        sex As String
        age As Integer
        add As String
        job As String
    End Type
    
    Sub macro1()
        'オブジェクトの定義
        Dim tanaka As personalInfo
        
        'フィールドの初期化
        tanaka.name = "T.Tanaka"
        tanaka.sex = "male"
        tanaka.age = 30
        tanaka.add = "Tokyo"
        tanaka.job = "teacher"
        
        MsgBox tanaka.name & "は" & tanaka.age & "歳で、" & _
                tanaka.add & "で" & tanaka.job & "をしています"
    End Sub

    実行結果:
    Type01

    ※「パブリック ユーザー定義型は定義できません」といったエラーが出る場合、Typeの宣言を標準モジュールで行うようにしましょう。

    このサンプルコードでは、Typeステートメントを使ってpersonalInfo型の構造体を宣言しています。そして、Dimステートメントを使ってオブジェクトtanakaを作成しています。

    オブジェクトtanakaからそれぞれのフィールドを呼び出して値を代入して、初期化しています。なお、Typeステートメントを使った構造体型の宣言はオブジェクトを作成するSubプロシージャの外に記述します。

    構造体を引数に指定する

    構造体をFunctionプロシージャの引数に指定すると引数の数を削減できて便利です。

    構造体のオブジェクトをFunctionプロシージャの引数で渡すには、ByRefステートメントを使って参照型で渡す必要があります。サンプルコードで確認しましょう。

    '構造体の宣言
    Type personalInfo
        name As String
        sex As String
        age As Integer
        add As String
        job As String
    End Type
    
    Sub macro2()
        'オブジェクトの定義
        Dim tanaka As personalInfo
        
        'フィールドの初期化
        tanaka.name = "T.Tanaka"
        tanaka.sex = "male"
        tanaka.age = 30
        tanaka.add = "Tokyo"
        tanaka.job = "teacher"
        
        msg tanaka
    End Sub
    
    Function msg(ByRef p As personalInfo)
        MsgBox p.name & "は" & p.age & "歳で、" & _
                p.add & "で" & p.job & "をしています"
    End Function

    実行結果:
    Type01

    このサンプルコードでは、Functionプロシージャを使ってMsgBoxを表示するmsg関数を定義しています。

    引数に構造体(ユーザー定義型)personalInfoを指定していますが、ByRefステートメントを使って参照型で渡すようにしています。構造体を引数に指定することで、変数を4つを引数に指定するよりも簡潔に関数を宣言することができています。

    なお、Functionプロシージャの使い方や引数の参照渡しについては、こちらで詳しく解説しています。ぜひ参考にしてください。

    配列の要素に構造体を指定する

    構造体を配列の要素に指定することが可能です。

    配列の要素に構造体を指定することで、さらにデータをひとかたまりで扱うことができて便利になります。サンプルコードで確認しましょう。

    Sub macro()
        'オブジェクトの定義
        Dim persons(3) As personalInfo
        
        'フィールドの初期化
        persons(0).name = "T.Tanaka"
        persons(0).sex = "male"
        persons(0).age = 30
        persons(0).add = "Tokyo"
        persons(0).job = "teacher"
        
        persons(1).name = "H.Yamada"
        persons(1).sex = "female"
        persons(1).age = 40
        persons(1).add = "Osaka"
        persons(1).job = "doctor"
        
        persons(2).name = "I.Suzuki"
        persons(2).sex = "male"
        persons(2).age = 20
        persons(2).add = "Nagoya"
        persons(2).job = "student"
        
        Dim i As Integer
        For i = LBound(persons) To UBound(persons) - 1
            msg persons(i)
        Next i
    End Sub
    
    Function msg(ByRef p As personalInfo)
        MsgBox p.name & "は" & p.age & "歳で、" & _
                p.add & "で" & p.job & "をしています"
    End Function

    実行結果:
    Type01
    Type02
    Type03

    配列の使い方については、こちらでまとめています。

    ぜひ参考にしてください。

    構造体をコピーする方法

    構造体のオブジェクトをコピーするには、別のオブジェクトに「=」記号を使って格納することでコピーすることができます。

    サンプルコードで確認しましょう。

    '構造体の宣言
    Type personalInfo
        name As String
        sex As String
        age As Integer
        add As String
        job As String
    End Type
    
    Sub macro3()
        'オブジェクトの定義
        Dim tanaka As personalInfo
        
        'フィールドの初期化
        tanaka.name = "T.Tanaka"
        tanaka.sex = "male"
        tanaka.age = 30
        tanaka.add = "Tokyo"
        tanaka.job = "teacher"
        
        Dim tanaka2 As personalInfo
        tanaka2 = tanaka 'コピー
        msg tanaka2
    End Sub
    
    Function msg(ByRef p As personalInfo)
        MsgBox p.name & "は" & p.age & "歳で、" & _
                p.add & "で" & p.job & "をしています"
    End Function

    実行結果:
    Type01

    構造体のフィールドで定数を定義する

    構造体のフィールドでConstステートメントを使って定数を定義しようとするとエラーが発生します。

    フィールドに定数を定義する代替手段として、定数列挙型で初期化する方法についてご紹介します。列挙型はEnumステートメントを使って宣言します。列挙型の変数には定数を指定することができます。

    ただし、列挙型の変数には長整数型の値しか指定できません。構造体のフィールドで長整数型の値を指定する場合は、次のように記述します。

    '構造体の宣言
    Type personalInfo
        name As String
        sex As String
        age As Integer
        add As String
        job As String
    End Type
    
    '列挙型の宣言、定義
    Enum myEnum
        age = 30
    End Enum
    
    Sub macro4()
        'オブジェクトの定義
        Dim tanaka As personalInfo
        
        'フィールドの初期化
        tanaka.name = "T.Tanaka"
        tanaka.sex = "male"
        tanaka.age = myEnum.age '定数を指定
        tanaka.add = "Tokyo"
        tanaka.job = "teacher"
        
        msg tanaka
    End Sub
    
    Function msg(ByRef p As personalInfo)
        MsgBox p.name & "は" & p.age & "歳で、" & _
                p.add & "で" & p.job & "をしています"
    End Function

    実行結果:
    Type01

    このサンプルコードでは、Enumステートメントを使って列挙型myEnumを宣言し、変数ageを定数で定義しています。

    personalInfo型のオブジェクトtanakaのフィールドageを呼び出し、myEnumの定数ageを格納しています。

    まとめ

    ここでは、構造体の使い方について説明しました。構造体を使うと複数のデータをひとまとまりに扱うことができて便利です。

    使いこなすことができるように、この記事を何度も参考にして下さいね!

    この記事を書いた人

    熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
    お問合せはこちらでも受け付けています。
    info@sss-lab.com

    目次