VBAの特徴
VBAはC言語などとは異なる点があります。
例えば、次のプログラムを実行した場合、表示されるのはbbbになります。
Sub uMain()
Dim a As String
a = "aaa"
uSub a
MsgBox a
End Sub
Sub uSub(a As String)
a = "bbb"
End Sub
そのため、SubやFunctionで引数を定義する場合、意図的に参照渡しをしないのであれば、引数定義の際にByValをつけることが必須です。原則、引数定義にはByValをつけると思っていたほうが良いでしょう。
次の定義でaaaが表示されるようになります。
Sub uSub(ByVal a As String)
a = "bbb"
End Sub
例えば、RangeオブジェクトにはValueというプロパティがあり、これがデフォルトプロパティになっています。これを使うと次のようにValueプロパティの記述を省略することが可能です。
Sub uMain()
ActiveWorkbook.ActiveSheet.Range("A1") = "aaa"
End Sub
これだけだと省略してもしなくてもと感じるかもしれませんが、セルからセルへの代入となるとこれが2倍になります。
また、ListObjectのItemプロパティの場合には効果が大きいです。受け取ったテーブルの金額列の1行目の値を表示するコードを基本通りに書くとこうなります。
Sub uSub(ByVal uList As ListObject)
MsgBox uList.ListColumns.Item("金額").DataBodyRange.Item(1).Value()
End Sub
デフォルトプロパティを使って指定すると次のように簡潔になります。
Sub uSub(ByVal uList As ListObject)
MsgBox uList.ListColumns("金額").DataBodyRange(1)
End Sub
ListColumnsもDataBodyRangeもItemがデフォルトプロパティなので、その指定を省略できるということです。上ではValueプロパティも省略しています。
次は、RangeプロパティをString型のuString変数に代入する場合と、Rangeオブジェクト型のuCell 変数に対する代入する場合の違いです。
Sub uSub()
Dim uString As String
Dim uCell As Range
uString = Range("A1")
Set uCell = Range("A1")
uCell.Interior.Color = vbRed
End Sub
uStringに対しては、Rangeプロパティの値が代入されています。
それに対してSetステートメントを使ったuCellに対してはRangeプロパティのアドレスが代入されています。
その結果、次の行で、uCellの色を変更することが出来ています。Setステートメントを使うことによりアドレスを代入するか、値を代入するかが違ってくるのでこの使い分けはとても注意する必要があります。
次のuAddファンクションの呼び出し方はいずれもエラーで、「コンパイルエラー、修正候補:ステートメントの最後」、が表示されます。
Sub uMain()
Dim a As Long
Dim b As Long
Dim c As Long
c = uAdd a, b
uadd(a,b)
End Sub
Function uAdd(ByVal uA As Long, ByVal uB As Long) As Long
uAdd = a + b
End Function
VBAを使い始めた頃に結構ハマるところなので注意が必要です。
このあたりはPascal言語も同様だったと記憶しています。
変数に対して型指定をしないと、このバリアント型になってしまいます。
バリアント型は問題を引き起こしやすいしインテリセンスが効かず開発効率も損ねるので型指定をすることを強くおすすめします。
これはOption Explicitのところで説明します。
以下の例では、uCellを指定して、そのプロパティを設定しています。
Sub uSub()
Dim uCell As Range
Set uCell = Range("A1")
With uCell
.Interior.Color = vbRed
.Formula = "=B1*2"
.Font.Italic = True
.Font.Bold = True
End With
End Sub
withがわかりにくいから使用禁止という人もいるようですが、それは相対パスがわかりにくいから使用禁止というようなものです。
慣れの問題で、慣れれば簡潔にコードを書くことが出来ます。簡潔に書けるということは、それだけタイプミスなどの問題も回避できるということです。
引数がデフォルトで参照渡し
VBAで関数に引数を渡す場合、デフォルトでは参照渡しになってしまいます。つまり呼び出された関数で呼び出した側の関数の変数を変更できてしまうという問題があります。例えば、次のプログラムを実行した場合、表示されるのはbbbになります。
Sub uMain()
Dim a As String
a = "aaa"
uSub a
MsgBox a
End Sub
Sub uSub(a As String)
a = "bbb"
End Sub
そのため、SubやFunctionで引数を定義する場合、意図的に参照渡しをしないのであれば、引数定義の際にByValをつけることが必須です。原則、引数定義にはByValをつけると思っていたほうが良いでしょう。
次の定義でaaaが表示されるようになります。
Sub uSub(ByVal a As String)
a = "bbb"
End Sub
デフォルトプロパティの使用
オブジェクトにはデフォルトプロパティをもつものがあり、オブジェクを参照した場合、そのデフォルトプロパティへの参照に置き換えられる場合があります。例えば、RangeオブジェクトにはValueというプロパティがあり、これがデフォルトプロパティになっています。これを使うと次のようにValueプロパティの記述を省略することが可能です。
Sub uMain()
ActiveWorkbook.ActiveSheet.Range("A1") = "aaa"
End Sub
これだけだと省略してもしなくてもと感じるかもしれませんが、セルからセルへの代入となるとこれが2倍になります。
また、ListObjectのItemプロパティの場合には効果が大きいです。受け取ったテーブルの金額列の1行目の値を表示するコードを基本通りに書くとこうなります。
Sub uSub(ByVal uList As ListObject)
MsgBox uList.ListColumns.Item("金額").DataBodyRange.Item(1).Value()
End Sub
デフォルトプロパティを使って指定すると次のように簡潔になります。
Sub uSub(ByVal uList As ListObject)
MsgBox uList.ListColumns("金額").DataBodyRange(1)
End Sub
ListColumnsもDataBodyRangeもItemがデフォルトプロパティなので、その指定を省略できるということです。上ではValueプロパティも省略しています。
オブジェクトとそれ以外の変数で代入の仕方が異なる
VBAでは、オブジェクトのアドレスを代入する場合とそれ以外を代入する場合で代入の仕方が異なります。次は、RangeプロパティをString型のuString変数に代入する場合と、Rangeオブジェクト型のuCell 変数に対する代入する場合の違いです。
Sub uSub()
Dim uString As String
Dim uCell As Range
uString = Range("A1")
Set uCell = Range("A1")
uCell.Interior.Color = vbRed
End Sub
uStringに対しては、Rangeプロパティの値が代入されています。
それに対してSetステートメントを使ったuCellに対してはRangeプロパティのアドレスが代入されています。
その結果、次の行で、uCellの色を変更することが出来ています。Setステートメントを使うことによりアドレスを代入するか、値を代入するかが違ってくるのでこの使い分けはとても注意する必要があります。
戻り値を得るかどうかで関数の呼び方が異なる
VBAは戻り値を得る場合には引数にカッコを付けて呼び出します。しかし、戻り値を得ない場合にはカッコを付けてはいけません。次のuAddファンクションの呼び出し方はいずれもエラーで、「コンパイルエラー、修正候補:ステートメントの最後」、が表示されます。
Sub uMain()
Dim a As Long
Dim b As Long
Dim c As Long
c = uAdd a, b
uadd(a,b)
End Sub
Function uAdd(ByVal uA As Long, ByVal uB As Long) As Long
uAdd = a + b
End Function
VBAを使い始めた頃に結構ハマるところなので注意が必要です。
SubとFunction
VBAでは、戻り値を返さない関数はSubプロシージャー、返す関数にはFunctionを使います。このあたりはPascal言語も同様だったと記憶しています。
バリアント型
VBAにはVariant型という何でもかんでも代入できて便利ではあるけれど問題もある変数型があります。変数に対して型指定をしないと、このバリアント型になってしまいます。
バリアント型は問題を引き起こしやすいしインテリセンスが効かず開発効率も損ねるので型指定をすることを強くおすすめします。
これはOption Explicitのところで説明します。
With ステートメント
オブジェクトを指定することで、withからend withまでの間は、指定したオブジェクトから相対的にプロパティやメソッドを指定できるステートメントです。以下の例では、uCellを指定して、そのプロパティを設定しています。
Sub uSub()
Dim uCell As Range
Set uCell = Range("A1")
With uCell
.Interior.Color = vbRed
.Formula = "=B1*2"
.Font.Italic = True
.Font.Bold = True
End With
End Sub
withがわかりにくいから使用禁止という人もいるようですが、それは相対パスがわかりにくいから使用禁止というようなものです。
慣れの問題で、慣れれば簡潔にコードを書くことが出来ます。簡潔に書けるということは、それだけタイプミスなどの問題も回避できるということです。
コメント
コメントを投稿