変数について

このエントリーをはてなブックマークに追加  


型の変更


今までのVB6やVBAと、VB 2005で変数の型名称が変わっています。

VB6/VBAVB 2005最小値最大値
 Integer Short -32,768 32,767
 Long Integer -2,147,483,648 2,147,483,647
 (なし) Long いっぱい いっぱい

変数宣言のルール


宣言のルールが変わりました。今までは、複数の変数を宣言するとき、変数ごとに型を指定しなければなりませんでした。
Long型の変数Aと、Long型の変数Bの二つを宣言する場合は次のように記述しました。

Dim A As Long, B As Long

これを次のようにすると、

Dim A, B As Long    ''変数Aはバリアント型

変数BはLong型になりますが、変数Aは型の指定を省略したとみなされてバリアント型となりました。
VB 2005では、同じ型の変数をまとめて宣言できるようになったため、次の記述で、Integer型の変数Aと、Integer型の変数Bを宣言できます。

Dim A, B As Integer    ''変数AはInteger型

たとえば、文字列"A,B,C"をカンマ(,)で分割するようなとき、今までは次のようなコードで問題なく実行できました。

Sub Sample()
    Dim tmp, i As Long
    tmp = Split("A,B,C", ",")
    For i = 0 To 2
        MsgBox tmp(i)
    Next i
End Sub

変数tmpは型指定を省略しているとみなされるため、バリアント型になりました。バリアント型には配列を格納することもできますから、Split関数の結果を配列として格納しています。このコードが正常に動作するのは、

(1)変数tmpは型の指定を省略したとみなされる
(2)型の指定を省略した変数はバリアント型になる

という前提です。ところがVB 2005では、変数tmpがLong型で宣言されるため、配列を格納することができずエラーになります。
なおVB 2005では、型の指定を省略するとオブジェクト型となります。

初期化


VB 2005では、変数の宣言時に初期値を設定できます。

Sub Sample()
    Dim buf As String = "tanaka"
    MsgBox(buf)
End Sub

初期値の設定は必須ではありませんが、たとえば次のようなケースで警告が出ます。

Sub Sample()
    Dim i As Integer, buf As String
    For i = 1 To 3
        buf &= "Sample" & vbCrLf
    Next
End Sub



これは、VBAでは次のようなコードです。

Sub Sample()
    Dim i As Long, buf As String
    For i = 1 To 3
        buf = buf & "Sample" & vbCrLf
    Next i
End Sub

buf &= "Sample" (buf = buf & "Sample") が最初に実行されるとき、変数bufはまだ初期化されていません。初期化されていない変数bufに値を代入するだけでなく、変数bufの値を参照しようとしているため「初期化されていない変数を参照している」という警告が発生するわけです。警告ですからビルドは終了して実行できますが、何となく気持ち悪いと感じる人は、変数の宣言時に初期化するクセを身につけた方がいいでしょう。


変数のプロパティ・メソッド


VB 2005では、変数もひとつのオブジェクトとして扱われますので、変数にもプロパティがあります。たとえば、変数に格納されている文字列の長さを調べるとき、VBAでは次のようにしました。

Sub Sample()
    Dim buf As String
    buf = "tanaka"
    MsgBox Len(buf)     ''結果は「6」
End Sub

文字列が格納されている変数を、文字列の長さを返すLen関数に渡すことで、Len関数が長さを返します。
VB 2005では、変数自体に長さを表すプロパティが用意されていますので、次のようにします。

Sub Sample()
    Dim buf As String
    buf = "tanaka"
    MsgBox(buf.Length)      ''結果は「6」
End Sub

ほかにも、たとえば"Microsoft Excel"から半角スペースの位置を調べ、そこから後ろ5文字を抜き出すとき、VBAでは次のようにしました。

Sub Sample()
    Dim buf As String
    buf = "Microsoft Excel"
    MsgBox Mid(buf, InStr(buf, " ") + 1, 5)
End Sub

これが、VB 2005では次のようになります。

Sub Sample()
    Dim buf As String
    buf = "Microsoft Excel"
    MsgBox(buf.Substring(buf.IndexOf(" ") + 1, 5))
End Sub

何型の変数にどんなプロパティやメソッドが用意されているかは、MSDNなどをご覧ください。ここでは、いくつかの例をお見せします。

左端の文字を抜き出す
Sub Sample()
    Dim buf As String
    buf = "Microsoft Excel"
    If Left(buf, 1) = "M" Then
        MsgBox buf & vbCrLf & "の先頭文字はMです"
    End If
End Sub

Sub Sample()
    Dim buf As String
    buf = "Microsoft Excel"
    If buf.StartsWith("M") Then
        MsgBox(buf & vbCrLf & "の先頭文字はMです")
    End If
End Sub

文字列を分割する
Sub Sample()
    Dim buf As String, tmp() As String
    buf = "田中,鈴木,山田"
    tmp = Split(buf, ",")
    MsgBox tmp(1)           ''結果は「鈴木」
End Sub

Sub Sample()
    Dim buf, tmp() As String
    buf = "田中,鈴木,山田"
    tmp = buf.Split(",")
    MsgBox(tmp(1))          ''結果は「鈴木」
End Sub

文字列の左にある指定文字を削除する
Sub Sample()
    Dim buf As String
    buf = "AAA田中AAA"
    MsgBox(buf.TrimStart("A"))      ''結果は「田中AAA」
End Sub

今までのTrim関数は空白を除去することしかできませんでしたが、TrimStartやTrimEndは、文字列の先頭や末尾などから、指定した文字を除去できます。


ブロックレベル変数


VB 2005ではブロックレベルの変数という仕組みがあります。たとえば次のコードで、変数bufはFor..Next内でのみ有効です。

Sub Sample()
    Dim i As Integer
    For i = 1 To 5
        Dim buf As String
        buf &= "+"
        Debug.Print(buf)    ''(1)正常
    Next
    MsgBox(buf)             ''(2)エラー
End Sub

変数bufは、For..Nextの内部で宣言されていますので、For..Nextの内部でのみ使用できます。(1)のDebug.Print(buf) は問題ありませんが、(2)のMsgBox(buf) は「変数が宣言されていない」ということでビルドエラーになります。

ブロックレベル変数は、For..Nextだけでなく、With..End WithやDo..Loop内でも使用できます。

また、ブロックレベル変数は、次のように使うこともできます。

Sub Sample()
    For i As Integer = 1 To 5
        Debug.Print(i)
    Next
End Sub

Forループの前に、カウンタ変数iを宣言する必要はありません。この変数iはブロックレベル変数となりますので、次のように書くとエラーになります。

Sub Sample()
    For i As Integer = 1 To 5
        Debug.Print(i)
    Next
    MsgBox(i)    ''エラー「名前'i'は宣言されていません」
End Sub

もちろん、次のようにFor Eachで使うことも可能です。

Sub Sample()
    Dim buf As String = "a,b,c"
    Dim tmp() As String = buf.Split(",")
    For Each c As String In tmp
        Debug.Print(c)
    Next
End Sub


配列


VS 2005ではOption Baseをサポートしていませんので、配列の下限値は常に0です。
配列の要素数を調べるのに、VBAではUBound関数を使いましたが、VB 2005ではUBound関数以外に、配列のLengthプロパティで要素数を取得できます。

Sub Sample()
    Dim buf(2) As String, i As Long
    buf(0) = "tanaka"
    buf(1) = "yamada"
    buf(2) = "suzuki"
    For i = 0 To UBound(buf)
        Debug.Print buf(i)
    Next i
End Sub

Sub Sample()
    Dim buf(2) As String, i As Long
    buf(0) = "tanaka"
    buf(1) = "yamada"
    buf(2) = "suzuki"
    For i = 0 To buf.Length - 1
        Debug.Print(buf(i))
    Next i
End Sub

また、次のように宣言時に配列を初期化することも可能です。

Sub Sample()
    Dim i As Long, buf() As String = {"tanaka", "yamada", "suzuki"}
    For i = 0 To buf.Length - 1
        Debug.Print(buf(i))
    Next i
End Sub

VBAでは、要素数を指定しないで宣言した動的配列に限って、ReDimステートメントで要素数を変更できました。
VB 2005では、要素数を指定して宣言した一般的な配列であっても、ReDimステートメントで要素数を変更できます。

Sub Sample()
    Dim buf(2) As String, i As Long
    buf(0) = "tanaka"
    buf(1) = "yamada"
    buf(2) = "suzuki"
    ReDim Preserve buf(3)       ''エラー
    buf(3) = "ono"
    For i = 0 To UBound(buf)
        Debug.Print buf(i)
    Next i
End Sub

Sub Sample()
    Dim buf(2) As String, i As Integer
    buf(0) = "tanaka"
    buf(1) = "yamada"
    buf(2) = "suzuki"
    ReDim Preserve buf(3)       ''正常
    buf(3) = "ono"
    For i = 0 To buf.Length - 1
        Debug.Print(buf(i))
    Next i
End Sub

配列を定義しているArrayクラスには、便利なメソッドが用意されています。次のコードは、配列をソートします。

Sub Sample()
    Dim buf(2) As String, i As Integer, msg As String = ""
    buf(0) = "tanaka"
    buf(1) = "yamada"
    buf(2) = "suzuki"
    Array.Sort(buf)
    For i = 0 To buf.Length - 1
        msg &= buf(i) & vbCrLf
    Next i
    MsgBox(msg)
End Sub



Reverseメソッドは配列を逆順にします。また、BinarySearchメソッドは、配列の中から指定した要素を検索し、見つかったインデックス値を返します。次のコードは、要素数が少ないのであまり意味がありませんけど、まぁ、こういうことです。

Sub Sample()
    Dim buf(2) As String, i As Integer
    buf(0) = "tanaka"
    buf(1) = "yamada"
    buf(2) = "suzuki"
    i = Array.BinarySearch(buf, "yamada")
    MsgBox(buf(i))
End Sub


構造体


構造体は、VBAで"ユーザー定義型"と呼ばれていました。VB 2005の構造体は、Type..End Typeではなく、Structureステートメントを使って定義します。

Type myData
    A As Long
    B As Long
End Type

Sub Sample()
    Dim buf As myData
    buf.A = 1
    buf.B = 2
    Debug.Print buf.A + buf.B
End Sub

Structure myData
    Dim A As Integer
    Dim B As Integer
End Structure

Sub Sample()
    Dim buf As myData
    buf.A = 1
    buf.B = 2
    Debug.Print(buf.A + buf.B)
End Sub

VB 2005の構造体には、独自のメソッドを定義できます。

Structure myData
    Dim A As Integer
    Dim B As Integer

    Function SUM() As Long
        SUM = A + B
    End Function
End Structure

Sub Sample()
    Dim buf As myData
    buf.A = 1
    buf.B = 2
    Debug.Print(buf.SUM)
End Sub


(何か思いついたら追記します)

このエントリーをはてなブックマークに追加